Merge branch 'sched/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Jul 2008 20:54:49 +0000 (13:54 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Jul 2008 20:54:49 +0000 (13:54 -0700)
* 'sched/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (76 commits)
  sched_clock: and multiplier for TSC to gtod drift
  sched_clock: record TSC after gtod
  sched_clock: only update deltas with local reads.
  sched_clock: fix calculation of other CPU
  sched_clock: stop maximum check on NO HZ
  sched_clock: widen the max and min time
  sched_clock: record from last tick
  sched: fix accounting in task delay accounting & migration
  sched: add avg-overlap support to RT tasks
  sched: terminate newidle balancing once at least one task has moved over
  sched: fix warning
  sched: build fix
  sched: sched_clock_cpu() based cpu_clock(), lockdep fix
  sched: export cpu_clock
  sched: make sched_{rt,fair}.c ifdefs more readable
  sched: bias effective_load() error towards failing wake_affine().
  sched: incremental effective_load()
  sched: correct wakeup weight calculations
  sched: fix mult overflow
  sched: update shares on wakeup
  ...

1044 files changed:
Documentation/ABI/testing/sysfs-block
Documentation/ABI/testing/sysfs-bus-css [new file with mode: 0644]
Documentation/ABI/testing/sysfs-firmware-memmap [new file with mode: 0644]
Documentation/block/data-integrity.txt [new file with mode: 0644]
Documentation/ioctl-number.txt
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/nmi_watchdog.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/x86/i386/IO-APIC.txt [moved from Documentation/i386/IO-APIC.txt with 100% similarity]
Documentation/x86/i386/boot.txt [moved from Documentation/i386/boot.txt with 96% similarity]
Documentation/x86/i386/usb-legacy-support.txt [moved from Documentation/i386/usb-legacy-support.txt with 100% similarity]
Documentation/x86/i386/zero-page.txt [moved from Documentation/i386/zero-page.txt with 100% similarity]
Documentation/x86/x86_64/00-INDEX [moved from Documentation/x86_64/00-INDEX with 100% similarity]
Documentation/x86/x86_64/boot-options.txt [moved from Documentation/x86_64/boot-options.txt with 100% similarity]
Documentation/x86/x86_64/cpu-hotplug-spec [moved from Documentation/x86_64/cpu-hotplug-spec with 100% similarity]
Documentation/x86/x86_64/fake-numa-for-cpusets [moved from Documentation/x86_64/fake-numa-for-cpusets with 100% similarity]
Documentation/x86/x86_64/kernel-stacks [moved from Documentation/x86_64/kernel-stacks with 100% similarity]
Documentation/x86/x86_64/machinecheck [moved from Documentation/x86_64/machinecheck with 100% similarity]
Documentation/x86/x86_64/mm.txt [moved from Documentation/x86_64/mm.txt with 87% similarity]
Documentation/x86/x86_64/uefi.txt [moved from Documentation/x86_64/uefi.txt with 84% similarity]
MAINTAINERS
arch/avr32/Kconfig
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/boards/atstk1000/atstk1003.c
arch/avr32/boards/atstk1000/atstk1004.c
arch/avr32/kernel/entry-avr32b.S
arch/avr32/kernel/signal.c
arch/avr32/kernel/time.c
arch/avr32/kernel/vmlinux.lds.S
arch/avr32/lib/io-readsb.S
arch/avr32/mach-at32ap/Makefile
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/intc.c
arch/avr32/mach-at32ap/pdc.c [moved from arch/avr32/mach-at32ap/at32ap.c with 90% similarity]
arch/avr32/mach-at32ap/pio.c
arch/avr32/mach-at32ap/pio.h
arch/avr32/mach-at32ap/pm-at32ap700x.S
arch/avr32/mach-at32ap/pm.c [new file with mode: 0644]
arch/avr32/mach-at32ap/sdramc.h [new file with mode: 0644]
arch/avr32/mm/init.c
arch/avr32/mm/tlb.c
arch/s390/Kconfig
arch/s390/appldata/appldata.h
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/appldata/appldata_os.c
arch/s390/crypto/crypt_s390.h
arch/s390/crypto/prng.c
arch/s390/hypfs/inode.c
arch/s390/kernel/Makefile
arch/s390/kernel/binfmt_elf32.c [deleted file]
arch/s390/kernel/compat_ptrace.h
arch/s390/kernel/debug.c
arch/s390/kernel/early.c
arch/s390/kernel/ipl.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/mem_detect.c [new file with mode: 0644]
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/setup.c
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/vtime.c
arch/s390/mm/init.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/a20.c
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/relocs.c
arch/x86/boot/cpu.c
arch/x86/boot/main.c
arch/x86/boot/memory.c
arch/x86/boot/pmjump.S
arch/x86/boot/video-vga.c
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/ia32/ia32entry.S
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/amd_iommu.c [new file with mode: 0644]
arch/x86/kernel/amd_iommu_init.c [new file with mode: 0644]
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic_32.c
arch/x86/kernel/apic_64.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/addon_cpuid_features.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/amd_64.c [new file with mode: 0644]
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/bugs_64.c [moved from arch/x86/kernel/bugs_64.c with 100% similarity]
arch/x86/kernel/cpu/centaur_64.c [new file with mode: 0644]
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/common_64.c [new file with mode: 0644]
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_64.c [new file with mode: 0644]
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/k7.c
arch/x86/kernel/cpu/mcheck/mce_64.c
arch/x86/kernel/cpu/mcheck/p4.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/perfctr-watchdog.c
arch/x86/kernel/e820.c [new file with mode: 0644]
arch/x86/kernel/e820_32.c [deleted file]
arch/x86/kernel/e820_64.c [deleted file]
arch/x86/kernel/early-quirks.c
arch/x86/kernel/efi.c
arch/x86/kernel/efi_64.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/genapic_64.c
arch/x86/kernel/genx2apic_uv_x.c
arch/x86/kernel/head.c [new file with mode: 0644]
arch/x86/kernel/head32.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/hpet.c
arch/x86/kernel/i387.c
arch/x86/kernel/i8259.c [moved from arch/x86/kernel/i8259_32.c with 70% similarity]
arch/x86/kernel/i8259_64.c [deleted file]
arch/x86/kernel/io_apic_32.c
arch/x86/kernel/io_apic_64.c
arch/x86/kernel/ipi.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/irq_64.c
arch/x86/kernel/irqinit_32.c [new file with mode: 0644]
arch/x86/kernel/irqinit_64.c [new file with mode: 0644]
arch/x86/kernel/ldt.c
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/microcode.c
arch/x86/kernel/mmconf-fam10h_64.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/nmi.c [moved from arch/x86/kernel/nmi_32.c with 68% similarity]
arch/x86/kernel/nmi_64.c [deleted file]
arch/x86/kernel/numaq_32.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/paravirt_patch_32.c
arch/x86/kernel/paravirt_patch_64.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/pci-swiotlb_64.c
arch/x86/kernel/probe_roms_32.c [new file with mode: 0644]
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/reboot_fixups_32.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup64.c [deleted file]
arch/x86/kernel/setup_32.c [deleted file]
arch/x86/kernel/setup_64.c [deleted file]
arch/x86/kernel/setup_percpu.c [new file with mode: 0644]
arch/x86/kernel/smpboot.c
arch/x86/kernel/summit_32.c
arch/x86/kernel/sys_i386_32.c
arch/x86/kernel/time_32.c
arch/x86/kernel/time_64.c
arch/x86/kernel/tlb_64.c
arch/x86/kernel/tlb_uv.c [new file with mode: 0644]
arch/x86/kernel/trampoline.c
arch/x86/kernel/traps_32.c
arch/x86/kernel/traps_64.c
arch/x86/kernel/tsc.c [new file with mode: 0644]
arch/x86/kernel/tsc_32.c [deleted file]
arch/x86/kernel/tsc_64.c [deleted file]
arch/x86/kernel/visws_quirks.c [new file with mode: 0644]
arch/x86/kernel/vmi_32.c
arch/x86/kernel/vmiclock_32.c
arch/x86/kernel/vmlinux_32.lds.S
arch/x86/kernel/vmlinux_64.lds.S
arch/x86/kernel/vsmp_64.c
arch/x86/kernel/vsyscall_64.c
arch/x86/kernel/x8664_ksyms_64.c
arch/x86/lguest/Kconfig
arch/x86/lguest/boot.c
arch/x86/lib/Makefile
arch/x86/lib/copy_user_64.S
arch/x86/lib/copy_user_nocache_64.S
arch/x86/lib/delay.c [moved from arch/x86/lib/delay_32.c with 88% similarity]
arch/x86/lib/delay_64.c [deleted file]
arch/x86/lib/getuser.S [moved from arch/x86/lib/getuser_64.S with 53% similarity]
arch/x86/lib/getuser_32.S [deleted file]
arch/x86/lib/putuser.S [moved from arch/x86/lib/putuser_32.S with 54% similarity]
arch/x86/lib/putuser_64.S [deleted file]
arch/x86/lib/usercopy_64.c
arch/x86/mach-default/setup.c
arch/x86/mach-es7000/Makefile
arch/x86/mach-es7000/es7000plat.c
arch/x86/mach-generic/Makefile
arch/x86/mach-generic/bigsmp.c
arch/x86/mach-generic/numaq.c [new file with mode: 0644]
arch/x86/mach-generic/probe.c
arch/x86/mach-visws/Makefile [deleted file]
arch/x86/mach-visws/mpparse.c [deleted file]
arch/x86/mach-visws/reboot.c [deleted file]
arch/x86/mach-visws/setup.c [deleted file]
arch/x86/mach-visws/traps.c [deleted file]
arch/x86/mach-visws/visws_apic.c [deleted file]
arch/x86/mach-voyager/setup.c
arch/x86/mach-voyager/voyager_smp.c
arch/x86/math-emu/reg_constant.c
arch/x86/mm/Makefile
arch/x86/mm/discontig_32.c
arch/x86/mm/dump_pagetables.c
arch/x86/mm/fault.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/k8topology_64.c
arch/x86/mm/numa_64.c
arch/x86/mm/pageattr-test.c
arch/x86/mm/pageattr.c
arch/x86/mm/pat.c
arch/x86/mm/pgtable.c
arch/x86/mm/pgtable_32.c
arch/x86/mm/srat_32.c [moved from arch/x86/kernel/srat_32.c with 56% similarity]
arch/x86/mm/srat_64.c
arch/x86/oprofile/nmi_int.c
arch/x86/pci/Makefile
arch/x86/pci/Makefile_32 [deleted file]
arch/x86/pci/Makefile_64 [deleted file]
arch/x86/pci/acpi.c
arch/x86/pci/amd_bus.c [moved from arch/x86/pci/k8-bus_64.c with 91% similarity]
arch/x86/pci/common.c
arch/x86/pci/direct.c
arch/x86/pci/i386.c
arch/x86/pci/init.c
arch/x86/pci/irq.c
arch/x86/pci/legacy.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mp_bus_to_node.c [deleted file]
arch/x86/pci/numa.c
arch/x86/pci/pci.h
arch/x86/pci/visws.c
arch/x86/power/hibernate_64.c
arch/x86/vdso/vdso32-setup.c
arch/x86/vdso/vma.c
arch/x86/xen/Kconfig
arch/x86/xen/Makefile
arch/x86/xen/enlighten.c
arch/x86/xen/manage.c [deleted file]
arch/x86/xen/mmu.c
arch/x86/xen/mmu.h
arch/x86/xen/multicalls.c
arch/x86/xen/multicalls.h
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/x86/xen/suspend.c [new file with mode: 0644]
arch/x86/xen/time.c
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
block/Kconfig
block/Makefile
block/as-iosched.c
block/blk-core.c
block/blk-integrity.c [new file with mode: 0644]
block/blk-map.c
block/blk-merge.c
block/blk-settings.c
block/blk.h
block/blktrace.c
block/bsg.c
block/cfq-iosched.c
block/cmd-filter.c [new file with mode: 0644]
block/elevator.c
block/genhd.c
block/scsi_ioctl.c
crypto/Kconfig
crypto/Makefile
crypto/ahash.c [new file with mode: 0644]
crypto/api.c
crypto/camellia.c
crypto/crc32c.c
crypto/cryptd.c
crypto/digest.c
crypto/hash.c
crypto/hmac.c
crypto/internal.h
crypto/prng.c [new file with mode: 0644]
crypto/prng.h [new file with mode: 0644]
crypto/ripemd.h [new file with mode: 0644]
crypto/rmd128.c [new file with mode: 0644]
crypto/rmd160.c [new file with mode: 0644]
crypto/rmd256.c [new file with mode: 0644]
crypto/rmd320.c [new file with mode: 0644]
crypto/tcrypt.c
crypto/tcrypt.h
drivers/Makefile
drivers/acpi/Kconfig
drivers/ata/libata-scsi.c
drivers/base/power/trace.c
drivers/base/topology.c
drivers/block/DAC960.c
drivers/block/aoe/aoecmd.c
drivers/block/paride/pt.c
drivers/block/pktcdvd.c
drivers/block/xen-blkfront.c
drivers/cdrom/cdrom.c
drivers/char/Makefile
drivers/char/agp/amd64-agp.c
drivers/char/drm/Makefile [deleted file]
drivers/char/hvc_xen.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/pcmcia/ipwireless/main.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/hifn_795x.c
drivers/crypto/ixp4xx_crypto.c [new file with mode: 0644]
drivers/crypto/padlock-aes.c
drivers/crypto/padlock-sha.c
drivers/crypto/talitos.c [new file with mode: 0644]
drivers/crypto/talitos.h [new file with mode: 0644]
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/dmi_scan.c
drivers/firmware/memmap.c [new file with mode: 0644]
drivers/gpu/Makefile [new file with mode: 0644]
drivers/gpu/drm/Kconfig [moved from drivers/char/drm/Kconfig with 100% similarity]
drivers/gpu/drm/Makefile [new file with mode: 0644]
drivers/gpu/drm/README.drm [moved from drivers/char/drm/README.drm with 100% similarity]
drivers/gpu/drm/ati_pcigart.c [moved from drivers/char/drm/ati_pcigart.c with 100% similarity]
drivers/gpu/drm/drm_agpsupport.c [moved from drivers/char/drm/drm_agpsupport.c with 100% similarity]
drivers/gpu/drm/drm_auth.c [moved from drivers/char/drm/drm_auth.c with 100% similarity]
drivers/gpu/drm/drm_bufs.c [moved from drivers/char/drm/drm_bufs.c with 100% similarity]
drivers/gpu/drm/drm_context.c [moved from drivers/char/drm/drm_context.c with 100% similarity]
drivers/gpu/drm/drm_dma.c [moved from drivers/char/drm/drm_dma.c with 100% similarity]
drivers/gpu/drm/drm_drawable.c [moved from drivers/char/drm/drm_drawable.c with 100% similarity]
drivers/gpu/drm/drm_drv.c [moved from drivers/char/drm/drm_drv.c with 100% similarity]
drivers/gpu/drm/drm_fops.c [moved from drivers/char/drm/drm_fops.c with 100% similarity]
drivers/gpu/drm/drm_hashtab.c [moved from drivers/char/drm/drm_hashtab.c with 100% similarity]
drivers/gpu/drm/drm_ioc32.c [moved from drivers/char/drm/drm_ioc32.c with 100% similarity]
drivers/gpu/drm/drm_ioctl.c [moved from drivers/char/drm/drm_ioctl.c with 100% similarity]
drivers/gpu/drm/drm_irq.c [moved from drivers/char/drm/drm_irq.c with 100% similarity]
drivers/gpu/drm/drm_lock.c [moved from drivers/char/drm/drm_lock.c with 100% similarity]
drivers/gpu/drm/drm_memory.c [moved from drivers/char/drm/drm_memory.c with 100% similarity]
drivers/gpu/drm/drm_mm.c [moved from drivers/char/drm/drm_mm.c with 100% similarity]
drivers/gpu/drm/drm_pci.c [moved from drivers/char/drm/drm_pci.c with 100% similarity]
drivers/gpu/drm/drm_proc.c [moved from drivers/char/drm/drm_proc.c with 100% similarity]
drivers/gpu/drm/drm_scatter.c [moved from drivers/char/drm/drm_scatter.c with 100% similarity]
drivers/gpu/drm/drm_sman.c [moved from drivers/char/drm/drm_sman.c with 100% similarity]
drivers/gpu/drm/drm_stub.c [moved from drivers/char/drm/drm_stub.c with 100% similarity]
drivers/gpu/drm/drm_sysfs.c [moved from drivers/char/drm/drm_sysfs.c with 100% similarity]
drivers/gpu/drm/drm_vm.c [moved from drivers/char/drm/drm_vm.c with 100% similarity]
drivers/gpu/drm/i810/Makefile [new file with mode: 0644]
drivers/gpu/drm/i810/i810_dma.c [moved from drivers/char/drm/i810_dma.c with 100% similarity]
drivers/gpu/drm/i810/i810_drv.c [moved from drivers/char/drm/i810_drv.c with 100% similarity]
drivers/gpu/drm/i810/i810_drv.h [moved from drivers/char/drm/i810_drv.h with 100% similarity]
drivers/gpu/drm/i830/Makefile [new file with mode: 0644]
drivers/gpu/drm/i830/i830_dma.c [moved from drivers/char/drm/i830_dma.c with 100% similarity]
drivers/gpu/drm/i830/i830_drv.c [moved from drivers/char/drm/i830_drv.c with 100% similarity]
drivers/gpu/drm/i830/i830_drv.h [moved from drivers/char/drm/i830_drv.h with 100% similarity]
drivers/gpu/drm/i830/i830_irq.c [moved from drivers/char/drm/i830_irq.c with 100% similarity]
drivers/gpu/drm/i915/Makefile [new file with mode: 0644]
drivers/gpu/drm/i915/i915_dma.c [moved from drivers/char/drm/i915_dma.c with 100% similarity]
drivers/gpu/drm/i915/i915_drv.c [moved from drivers/char/drm/i915_drv.c with 100% similarity]
drivers/gpu/drm/i915/i915_drv.h [moved from drivers/char/drm/i915_drv.h with 100% similarity]
drivers/gpu/drm/i915/i915_ioc32.c [moved from drivers/char/drm/i915_ioc32.c with 100% similarity]
drivers/gpu/drm/i915/i915_irq.c [moved from drivers/char/drm/i915_irq.c with 100% similarity]
drivers/gpu/drm/i915/i915_mem.c [moved from drivers/char/drm/i915_mem.c with 100% similarity]
drivers/gpu/drm/mga/Makefile [new file with mode: 0644]
drivers/gpu/drm/mga/mga_dma.c [moved from drivers/char/drm/mga_dma.c with 100% similarity]
drivers/gpu/drm/mga/mga_drv.c [moved from drivers/char/drm/mga_drv.c with 100% similarity]
drivers/gpu/drm/mga/mga_drv.h [moved from drivers/char/drm/mga_drv.h with 100% similarity]
drivers/gpu/drm/mga/mga_ioc32.c [moved from drivers/char/drm/mga_ioc32.c with 100% similarity]
drivers/gpu/drm/mga/mga_irq.c [moved from drivers/char/drm/mga_irq.c with 100% similarity]
drivers/gpu/drm/mga/mga_state.c [moved from drivers/char/drm/mga_state.c with 100% similarity]
drivers/gpu/drm/mga/mga_ucode.h [moved from drivers/char/drm/mga_ucode.h with 100% similarity]
drivers/gpu/drm/mga/mga_warp.c [moved from drivers/char/drm/mga_warp.c with 100% similarity]
drivers/gpu/drm/r128/Makefile [new file with mode: 0644]
drivers/gpu/drm/r128/r128_cce.c [moved from drivers/char/drm/r128_cce.c with 100% similarity]
drivers/gpu/drm/r128/r128_drv.c [moved from drivers/char/drm/r128_drv.c with 100% similarity]
drivers/gpu/drm/r128/r128_drv.h [moved from drivers/char/drm/r128_drv.h with 100% similarity]
drivers/gpu/drm/r128/r128_ioc32.c [moved from drivers/char/drm/r128_ioc32.c with 100% similarity]
drivers/gpu/drm/r128/r128_irq.c [moved from drivers/char/drm/r128_irq.c with 100% similarity]
drivers/gpu/drm/r128/r128_state.c [moved from drivers/char/drm/r128_state.c with 100% similarity]
drivers/gpu/drm/radeon/Makefile [new file with mode: 0644]
drivers/gpu/drm/radeon/r300_cmdbuf.c [moved from drivers/char/drm/r300_cmdbuf.c with 100% similarity]
drivers/gpu/drm/radeon/r300_reg.h [moved from drivers/char/drm/r300_reg.h with 100% similarity]
drivers/gpu/drm/radeon/radeon_cp.c [moved from drivers/char/drm/radeon_cp.c with 100% similarity]
drivers/gpu/drm/radeon/radeon_drv.c [moved from drivers/char/drm/radeon_drv.c with 100% similarity]
drivers/gpu/drm/radeon/radeon_drv.h [moved from drivers/char/drm/radeon_drv.h with 100% similarity]
drivers/gpu/drm/radeon/radeon_ioc32.c [moved from drivers/char/drm/radeon_ioc32.c with 100% similarity]
drivers/gpu/drm/radeon/radeon_irq.c [moved from drivers/char/drm/radeon_irq.c with 100% similarity]
drivers/gpu/drm/radeon/radeon_mem.c [moved from drivers/char/drm/radeon_mem.c with 100% similarity]
drivers/gpu/drm/radeon/radeon_microcode.h [moved from drivers/char/drm/radeon_microcode.h with 100% similarity]
drivers/gpu/drm/radeon/radeon_state.c [moved from drivers/char/drm/radeon_state.c with 100% similarity]
drivers/gpu/drm/savage/Makefile [new file with mode: 0644]
drivers/gpu/drm/savage/savage_bci.c [moved from drivers/char/drm/savage_bci.c with 100% similarity]
drivers/gpu/drm/savage/savage_drv.c [moved from drivers/char/drm/savage_drv.c with 100% similarity]
drivers/gpu/drm/savage/savage_drv.h [moved from drivers/char/drm/savage_drv.h with 100% similarity]
drivers/gpu/drm/savage/savage_state.c [moved from drivers/char/drm/savage_state.c with 100% similarity]
drivers/gpu/drm/sis/Makefile [new file with mode: 0644]
drivers/gpu/drm/sis/sis_drv.c [moved from drivers/char/drm/sis_drv.c with 100% similarity]
drivers/gpu/drm/sis/sis_drv.h [moved from drivers/char/drm/sis_drv.h with 100% similarity]
drivers/gpu/drm/sis/sis_mm.c [moved from drivers/char/drm/sis_mm.c with 100% similarity]
drivers/gpu/drm/tdfx/Makefile [new file with mode: 0644]
drivers/gpu/drm/tdfx/tdfx_drv.c [moved from drivers/char/drm/tdfx_drv.c with 100% similarity]
drivers/gpu/drm/tdfx/tdfx_drv.h [moved from drivers/char/drm/tdfx_drv.h with 100% similarity]
drivers/gpu/drm/via/Makefile [new file with mode: 0644]
drivers/gpu/drm/via/via_3d_reg.h [moved from drivers/char/drm/via_3d_reg.h with 100% similarity]
drivers/gpu/drm/via/via_dma.c [moved from drivers/char/drm/via_dma.c with 100% similarity]
drivers/gpu/drm/via/via_dmablit.c [moved from drivers/char/drm/via_dmablit.c with 100% similarity]
drivers/gpu/drm/via/via_dmablit.h [moved from drivers/char/drm/via_dmablit.h with 100% similarity]
drivers/gpu/drm/via/via_drv.c [moved from drivers/char/drm/via_drv.c with 100% similarity]
drivers/gpu/drm/via/via_drv.h [moved from drivers/char/drm/via_drv.h with 100% similarity]
drivers/gpu/drm/via/via_irq.c [moved from drivers/char/drm/via_irq.c with 100% similarity]
drivers/gpu/drm/via/via_map.c [moved from drivers/char/drm/via_map.c with 100% similarity]
drivers/gpu/drm/via/via_mm.c [moved from drivers/char/drm/via_mm.c with 100% similarity]
drivers/gpu/drm/via/via_verifier.c [moved from drivers/char/drm/via_verifier.c with 100% similarity]
drivers/gpu/drm/via/via_verifier.h [moved from drivers/char/drm/via_verifier.h with 100% similarity]
drivers/gpu/drm/via/via_video.c [moved from drivers/char/drm/via_video.c with 100% similarity]
drivers/ide/legacy/ide-cs.c
drivers/input/xen-kbdfront.c
drivers/lguest/Kconfig
drivers/lguest/lg.h
drivers/md/linear.c
drivers/md/raid0.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/misc/atmel_pwm.c
drivers/mtd/ftl.c
drivers/mtd/maps/pcmciamtd.c
drivers/net/macb.c
drivers/net/xen-netfront.c
drivers/pci/intel-iommu.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/au1000_generic.h
drivers/pcmcia/au1000_pb1x00.c
drivers/pcmcia/au1000_xxs1500.c
drivers/pcmcia/bfin_cf_pcmcia.c [new file with mode: 0644]
drivers/pcmcia/cardbus.c
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/hd64465_ss.c
drivers/pcmcia/i82092.c
drivers/pcmcia/i82092aa.h
drivers/pcmcia/i82365.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/soc_common.h
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/ti113x.h
drivers/rtc/rtc-at32ap700x.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.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/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/fs3270.c
drivers/s390/char/monreader.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.c
drivers/s390/char/sclp_cmd.c
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_config.c
drivers/s390/char/sclp_cpi_sys.c
drivers/s390/char/sclp_quiesce.c
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_sdias.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/sclp_tty.h
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_core.c
drivers/s390/char/tty3270.c
drivers/s390/char/vmcp.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/char/vmwatchdog.c
drivers/s390/char/zcore.c
drivers/s390/cio/Makefile
drivers/s390/cio/airq.c
drivers/s390/cio/chp.c
drivers/s390/cio/chp.h
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/chsc_sch.c [new file with mode: 0644]
drivers/s390/cio/chsc_sch.h [new file with mode: 0644]
drivers/s390/cio/cio.c
drivers/s390/cio/cio.h
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_id.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/device_pgid.c
drivers/s390/cio/device_status.c
drivers/s390/cio/fcx.c [new file with mode: 0644]
drivers/s390/cio/idset.h
drivers/s390/cio/io_sch.h
drivers/s390/cio/ioasm.h
drivers/s390/cio/isc.c [new file with mode: 0644]
drivers/s390/cio/itcw.c [new file with mode: 0644]
drivers/s390/cio/qdio.c
drivers/s390/cio/qdio.h
drivers/s390/cio/scsw.c [new file with mode: 0644]
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_cex2a.c
drivers/s390/crypto/zcrypt_error.h
drivers/s390/crypto/zcrypt_pcica.c
drivers/s390/crypto/zcrypt_pcicc.c
drivers/s390/crypto/zcrypt_pcixcc.c
drivers/s390/net/claw.c
drivers/s390/net/ctcm_fsms.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/cu3088.c
drivers/s390/net/cu3088.h
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/smsgiucv.c
drivers/s390/s390mach.c
drivers/s390/s390mach.h
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/serial/atmel_serial.c
drivers/video/Kconfig
drivers/video/sgivwfb.c
drivers/video/xen-fbfront.c
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events.c
drivers/xen/grant-table.c
drivers/xen/manage.c [new file with mode: 0644]
drivers/xen/xenbus/xenbus_client.c
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_xs.c
fs/Kconfig
fs/Makefile
fs/bio-integrity.c [new file with mode: 0644]
fs/bio.c
fs/namespace.c
fs/proc/base.c
fs/proc/proc_misc.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/ramfs/file-mmu.c
fs/ramfs/file-nommu.c
fs/splice.c
include/Kbuild
include/asm-avr32/arch-at32ap/board.h
include/asm-avr32/arch-at32ap/init.h
include/asm-avr32/arch-at32ap/pm.h
include/asm-avr32/arch-at32ap/sram.h [new file with mode: 0644]
include/asm-avr32/mmu_context.h
include/asm-avr32/pci.h
include/asm-avr32/pgalloc.h
include/asm-avr32/pgtable.h
include/asm-avr32/thread_info.h
include/asm-avr32/tlbflush.h
include/asm-generic/pgtable.h
include/asm-generic/topology.h
include/asm-generic/vmlinux.lds.h
include/asm-mips/mach-au1x00/au1xxx_psc.h
include/asm-s390/Kbuild
include/asm-s390/airq.h
include/asm-s390/ccwdev.h
include/asm-s390/chpid.h
include/asm-s390/chsc.h [new file with mode: 0644]
include/asm-s390/cio.h
include/asm-s390/elf.h
include/asm-s390/etr.h
include/asm-s390/fcx.h [new file with mode: 0644]
include/asm-s390/ipl.h
include/asm-s390/isc.h [new file with mode: 0644]
include/asm-s390/itcw.h [new file with mode: 0644]
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/ptrace.h
include/asm-s390/schid.h [moved from drivers/s390/cio/schid.h with 65% similarity]
include/asm-s390/sclp.h
include/asm-s390/setup.h
include/asm-s390/sparsemem.h
include/asm-s390/timer.h
include/asm-s390/zcrypt.h
include/asm-x86/acpi.h
include/asm-x86/amd_iommu.h [new file with mode: 0644]
include/asm-x86/amd_iommu_types.h [new file with mode: 0644]
include/asm-x86/apic.h
include/asm-x86/asm.h
include/asm-x86/atomic_64.h
include/asm-x86/bios_ebda.h
include/asm-x86/bitops.h
include/asm-x86/bootparam.h
include/asm-x86/cmpxchg_64.h
include/asm-x86/cpufeature.h
include/asm-x86/current.h
include/asm-x86/current_32.h [deleted file]
include/asm-x86/current_64.h [deleted file]
include/asm-x86/desc.h
include/asm-x86/desc_defs.h
include/asm-x86/dmi.h
include/asm-x86/dwarf2.h
include/asm-x86/dwarf2_32.h [deleted file]
include/asm-x86/dwarf2_64.h [deleted file]
include/asm-x86/e820.h
include/asm-x86/e820_32.h [deleted file]
include/asm-x86/e820_64.h [deleted file]
include/asm-x86/efi.h
include/asm-x86/elf.h
include/asm-x86/fixmap.h
include/asm-x86/fixmap_32.h
include/asm-x86/fixmap_64.h
include/asm-x86/gart.h
include/asm-x86/genapic_64.h
include/asm-x86/hardirq.h
include/asm-x86/highmem.h
include/asm-x86/hpet.h
include/asm-x86/hw_irq.h
include/asm-x86/hw_irq_32.h [deleted file]
include/asm-x86/hw_irq_64.h [deleted file]
include/asm-x86/i8259.h
include/asm-x86/io.h
include/asm-x86/io_32.h
include/asm-x86/io_64.h
include/asm-x86/io_apic.h
include/asm-x86/iommu.h
include/asm-x86/ipi.h
include/asm-x86/irq.h
include/asm-x86/irq_32.h [deleted file]
include/asm-x86/irq_64.h [deleted file]
include/asm-x86/irq_vectors.h [new file with mode: 0644]
include/asm-x86/irqflags.h
include/asm-x86/mach-bigsmp/mach_apic.h
include/asm-x86/mach-bigsmp/mach_mpspec.h [deleted file]
include/asm-x86/mach-default/irq_vectors.h [deleted file]
include/asm-x86/mach-default/irq_vectors_limits.h [deleted file]
include/asm-x86/mach-default/mach_apic.h
include/asm-x86/mach-default/setup_arch.h
include/asm-x86/mach-default/smpboot_hooks.h
include/asm-x86/mach-es7000/mach_mpspec.h [deleted file]
include/asm-x86/mach-generic/mach_mpparse.h
include/asm-x86/mach-numaq/mach_apic.h
include/asm-x86/mach-numaq/mach_mpparse.h
include/asm-x86/mach-numaq/mach_mpspec.h [deleted file]
include/asm-x86/mach-summit/mach_mpspec.h [deleted file]
include/asm-x86/mach-visws/irq_vectors.h [deleted file]
include/asm-x86/mach-visws/mach_apic.h
include/asm-x86/mach-visws/mach_apicdef.h
include/asm-x86/mach-visws/setup_arch.h
include/asm-x86/mach-visws/smpboot_hooks.h
include/asm-x86/mach-voyager/irq_vectors.h [deleted file]
include/asm-x86/mmconfig.h [new file with mode: 0644]
include/asm-x86/mmu_context.h
include/asm-x86/mmu_context_32.h
include/asm-x86/mmu_context_64.h
include/asm-x86/mmzone_32.h
include/asm-x86/mpspec.h
include/asm-x86/mpspec_def.h
include/asm-x86/msr-index.h
include/asm-x86/msr.h
include/asm-x86/nmi.h
include/asm-x86/numa_32.h
include/asm-x86/numa_64.h
include/asm-x86/numaq.h
include/asm-x86/page.h
include/asm-x86/page_32.h
include/asm-x86/page_64.h
include/asm-x86/paravirt.h
include/asm-x86/pat.h
include/asm-x86/pci.h
include/asm-x86/pci_32.h
include/asm-x86/pda.h
include/asm-x86/percpu.h
include/asm-x86/pgalloc.h
include/asm-x86/pgtable.h
include/asm-x86/pgtable_32.h
include/asm-x86/pgtable_64.h
include/asm-x86/processor-flags.h
include/asm-x86/processor.h
include/asm-x86/proto.h
include/asm-x86/ptrace.h
include/asm-x86/reboot.h
include/asm-x86/required-features.h
include/asm-x86/resume-trace.h
include/asm-x86/seccomp_32.h
include/asm-x86/seccomp_64.h
include/asm-x86/segment.h
include/asm-x86/setup.h
include/asm-x86/smp.h
include/asm-x86/srat.h
include/asm-x86/string_32.h
include/asm-x86/suspend_32.h
include/asm-x86/system.h
include/asm-x86/thread_info.h
include/asm-x86/thread_info_32.h [deleted file]
include/asm-x86/thread_info_64.h [deleted file]
include/asm-x86/time.h
include/asm-x86/timer.h
include/asm-x86/topology.h
include/asm-x86/tsc.h
include/asm-x86/uaccess.h
include/asm-x86/uaccess_32.h
include/asm-x86/uaccess_64.h
include/asm-x86/unistd_64.h
include/asm-x86/uv/uv_bau.h [new file with mode: 0644]
include/asm-x86/uv/uv_hub.h
include/asm-x86/uv/uv_mmrs.h
include/asm-x86/visws/cobalt.h [moved from include/asm-x86/mach-visws/cobalt.h with 100% similarity]
include/asm-x86/visws/lithium.h [moved from include/asm-x86/mach-visws/lithium.h with 100% similarity]
include/asm-x86/visws/piix4.h [moved from include/asm-x86/mach-visws/piix4.h with 100% similarity]
include/asm-x86/visws/sgivw.h [new file with mode: 0644]
include/asm-x86/vm86.h
include/asm-x86/vmi_time.h
include/asm-x86/xen/hypercall.h
include/asm-x86/xen/page.h
include/asm-x86/xor_32.h
include/asm-x86/xor_64.h
include/crypto/hash.h [new file with mode: 0644]
include/crypto/internal/hash.h [new file with mode: 0644]
include/drm/Kbuild [new file with mode: 0644]
include/drm/drm.h [moved from drivers/char/drm/drm.h with 100% similarity]
include/drm/drmP.h [moved from drivers/char/drm/drmP.h with 100% similarity]
include/drm/drm_core.h [moved from drivers/char/drm/drm_core.h with 100% similarity]
include/drm/drm_hashtab.h [moved from drivers/char/drm/drm_hashtab.h with 100% similarity]
include/drm/drm_memory.h [moved from drivers/char/drm/drm_memory.h with 100% similarity]
include/drm/drm_memory_debug.h [moved from drivers/char/drm/drm_memory_debug.h with 100% similarity]
include/drm/drm_os_linux.h [moved from drivers/char/drm/drm_os_linux.h with 100% similarity]
include/drm/drm_pciids.h [moved from drivers/char/drm/drm_pciids.h with 100% similarity]
include/drm/drm_sarea.h [moved from drivers/char/drm/drm_sarea.h with 100% similarity]
include/drm/drm_sman.h [moved from drivers/char/drm/drm_sman.h with 100% similarity]
include/drm/i810_drm.h [moved from drivers/char/drm/i810_drm.h with 100% similarity]
include/drm/i830_drm.h [moved from drivers/char/drm/i830_drm.h with 100% similarity]
include/drm/i915_drm.h [moved from drivers/char/drm/i915_drm.h with 100% similarity]
include/drm/mga_drm.h [moved from drivers/char/drm/mga_drm.h with 100% similarity]
include/drm/r128_drm.h [moved from drivers/char/drm/r128_drm.h with 100% similarity]
include/drm/radeon_drm.h [moved from drivers/char/drm/radeon_drm.h with 100% similarity]
include/drm/savage_drm.h [moved from drivers/char/drm/savage_drm.h with 100% similarity]
include/drm/sis_drm.h [moved from drivers/char/drm/sis_drm.h with 100% similarity]
include/drm/via_drm.h [moved from drivers/char/drm/via_drm.h with 100% similarity]
include/linux/acpi.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/bootmem.h
include/linux/console.h
include/linux/crypto.h
include/linux/delay.h
include/linux/efi.h
include/linux/firmware-map.h [new file with mode: 0644]
include/linux/genhd.h
include/linux/iocontext.h
include/linux/kernel_stat.h
include/linux/linkage.h
include/linux/mm.h
include/linux/mod_devicetable.h
include/linux/page-flags.h
include/linux/pageblock-flags.h
include/linux/ptrace.h
include/linux/resume-trace.h
include/linux/security.h
include/pcmcia/bulkmem.h [deleted file]
include/pcmcia/cistpl.h
include/pcmcia/cs.h
include/pcmcia/cs_types.h
include/pcmcia/ds.h
include/pcmcia/ss.h
include/pcmcia/version.h [deleted file]
include/sound/ad1843.h [new file with mode: 0644]
include/sound/control.h
include/sound/core.h
include/sound/cs4231-regs.h
include/sound/cs4231.h
include/sound/emu10k1.h
include/sound/seq_kernel.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/uda1341.h
include/sound/version.h
include/xen/events.h
include/xen/grant_table.h
include/xen/hvc-console.h
include/xen/interface/elfnote.h
include/xen/interface/features.h
include/xen/interface/io/fbif.h
include/xen/interface/io/kbdif.h
include/xen/interface/memory.h
include/xen/interface/xen.h
include/xen/xen-ops.h
init/calibrate.c
kernel/exit.c
kernel/fork.c
kernel/printk.c
kernel/ptrace.c
kernel/sched.c
kernel/time/tick-broadcast.c
mm/Kconfig
mm/mprotect.c
mm/page_alloc.c
mm/slub.c
net/iucv/af_iucv.c
net/iucv/iucv.c
scripts/mod/file2alias.c
security/Kconfig
security/Makefile
security/capability.c
security/commoncap.c
security/dummy.c [deleted file]
security/root_plug.c
security/security.c
security/selinux/hooks.c
security/selinux/include/audit.h
security/selinux/include/avc.h
security/selinux/include/objsec.h
security/selinux/include/security.h
security/selinux/netnode.c
security/selinux/netport.c
security/selinux/selinuxfs.c
security/selinux/ss/avtab.c
security/selinux/ss/context.h
security/selinux/ss/mls.c
security/selinux/ss/mls.h
security/selinux/ss/policydb.c
security/selinux/ss/services.c
security/selinux/ss/sidtab.c
security/selinux/ss/sidtab.h
security/smack/smack_lsm.c
sound/Kconfig
sound/aoa/Kconfig
sound/aoa/codecs/Kconfig
sound/aoa/fabrics/Kconfig
sound/aoa/soundbus/Kconfig
sound/arm/Kconfig
sound/arm/sa11xx-uda1341.c
sound/core/Kconfig
sound/core/control.c
sound/core/init.c
sound/core/memalloc.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_device.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/Kconfig
sound/drivers/vx/vx_hwdep.c
sound/i2c/cs8427.c
sound/i2c/l3/uda1341.c
sound/isa/Kconfig
sound/isa/cs423x/cs4231_lib.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/Makefile
sound/isa/wavefront/wavefront_synth.c
sound/mips/Kconfig
sound/mips/Makefile
sound/mips/ad1843.c [new file with mode: 0644]
sound/mips/hal2.c [new file with mode: 0644]
sound/mips/hal2.h [new file with mode: 0644]
sound/mips/sgio2audio.c [new file with mode: 0644]
sound/oss/Kconfig
sound/oss/dmasound/dmasound_core.c
sound/oss/dmasound/dmasound_paula.c
sound/oss/dmasound/dmasound_q40.c
sound/oss/msnd.c
sound/oss/msnd.h
sound/oss/msnd_classic.h
sound/oss/msnd_pinnacle.c
sound/oss/msnd_pinnacle.h
sound/oss/vwsnd.c
sound/parisc/Kconfig
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/ac97/Makefile
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ak4531_codec.c [moved from sound/pci/ac97/ak4531_codec.c with 96% similarity]
sound/pci/au88x0/au88x0_game.c
sound/pci/azt3328.c
sound/pci/azt3328.h
sound/pci/ca0106/ca0106_main.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/memory.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/envy24ht.h
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/maestro3.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/hifier.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/virtuoso.c
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr_core.c
sound/pci/trident/trident_main.c
sound/pci/trident/trident_memory.c
sound/pci/via82xx.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/Kconfig
sound/pcmcia/vx/vxp_ops.c
sound/ppc/Kconfig
sound/ppc/daca.c
sound/ppc/tumbler.c
sound/sh/Kconfig
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/at32/Kconfig [new file with mode: 0644]
sound/soc/at32/Makefile [new file with mode: 0644]
sound/soc/at32/at32-pcm.c [new file with mode: 0644]
sound/soc/at32/at32-pcm.h [new file with mode: 0644]
sound/soc/at32/at32-ssc.c [new file with mode: 0644]
sound/soc/at32/at32-ssc.h [new file with mode: 0644]
sound/soc/at32/playpaq_wm8510.c [new file with mode: 0644]
sound/soc/at91/Kconfig
sound/soc/at91/at91-pcm.c
sound/soc/at91/at91-ssc.c
sound/soc/at91/at91-ssc.h
sound/soc/at91/eti_b1_wm8731.c
sound/soc/au1x/Kconfig [new file with mode: 0644]
sound/soc/au1x/Makefile [new file with mode: 0644]
sound/soc/au1x/dbdma2.c [new file with mode: 0644]
sound/soc/au1x/psc-ac97.c [new file with mode: 0644]
sound/soc/au1x/psc-i2s.c [new file with mode: 0644]
sound/soc/au1x/psc.h [new file with mode: 0644]
sound/soc/au1x/sample-ac97.c [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ac97.h
sound/soc/codecs/ak4535.c [new file with mode: 0644]
sound/soc/codecs/ak4535.h [new file with mode: 0644]
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4270.h
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/uda1380.c [new file with mode: 0644]
sound/soc/codecs/uda1380.h [new file with mode: 0644]
sound/soc/codecs/wm8510.c [new file with mode: 0644]
sound/soc/codecs/wm8510.h [new file with mode: 0644]
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8731.h
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8750.h
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8990.c [new file with mode: 0644]
sound/soc/codecs/wm8990.h [new file with mode: 0644]
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9712.h
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm9713.h
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-i2s.h
sound/soc/davinci/davinci-pcm.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_dma.h
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_ssi.h
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/omap/Kconfig
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-pcm.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/corgi.c
sound/soc/pxa/em-x270.c [new file with mode: 0644]
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-ac97.h
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-i2s.h
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2412-i2s.h
sound/soc/s3c24xx/s3c2443-ac97.c
sound/soc/s3c24xx/s3c24xx-ac97.h
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx-i2s.h
sound/soc/s3c24xx/s3c24xx-pcm.c
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/sh/Kconfig
sound/soc/sh/dma-sh7760.c
sound/soc/sh/hac.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/sparc/Kconfig
sound/sparc/dbri.c
sound/spi/Kconfig
sound/usb/Kconfig
sound/usb/caiaq/caiaq-audio.c
sound/usb/caiaq/caiaq-device.c
sound/usb/caiaq/caiaq-device.h
sound/usb/usbaudio.c
sound/usb/usbquirks.h

index 4bd9ea539129036264b80dd926f156167bd51d6e..44f52a4f5903359eda2f2ffafff2d3341e437e62 100644 (file)
@@ -26,3 +26,37 @@ Description:
                I/O statistics of partition <part>. The format is the
                same as the above-written /sys/block/<disk>/stat
                format.
+
+
+What:          /sys/block/<disk>/integrity/format
+Date:          June 2008
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Metadata format for integrity capable block device.
+               E.g. T10-DIF-TYPE1-CRC.
+
+
+What:          /sys/block/<disk>/integrity/read_verify
+Date:          June 2008
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Indicates whether the block layer should verify the
+               integrity of read requests serviced by devices that
+               support sending integrity metadata.
+
+
+What:          /sys/block/<disk>/integrity/tag_size
+Date:          June 2008
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Number of bytes of integrity tag space available per
+               512 bytes of data.
+
+
+What:          /sys/block/<disk>/integrity/write_generate
+Date:          June 2008
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Indicates whether the block layer should automatically
+               generate checksums for write requests bound for
+               devices that support receiving integrity metadata.
diff --git a/Documentation/ABI/testing/sysfs-bus-css b/Documentation/ABI/testing/sysfs-bus-css
new file mode 100644 (file)
index 0000000..b585ec2
--- /dev/null
@@ -0,0 +1,35 @@
+What:          /sys/bus/css/devices/.../type
+Date:          March 2008
+Contact:       Cornelia Huck <cornelia.huck@de.ibm.com>
+               linux-s390@vger.kernel.org
+Description:   Contains the subchannel type, as reported by the hardware.
+               This attribute is present for all subchannel types.
+
+What:          /sys/bus/css/devices/.../modalias
+Date:          March 2008
+Contact:       Cornelia Huck <cornelia.huck@de.ibm.com>
+               linux-s390@vger.kernel.org
+Description:   Contains the module alias as reported with uevents.
+               It is of the format css:t<type> and present for all
+               subchannel types.
+
+What:          /sys/bus/css/drivers/io_subchannel/.../chpids
+Date:          December 2002
+Contact:       Cornelia Huck <cornelia.huck@de.ibm.com>
+               linux-s390@vger.kernel.org
+Description:   Contains the ids of the channel paths used by this
+               subchannel, as reported by the channel subsystem
+               during subchannel recognition.
+               Note: This is an I/O-subchannel specific attribute.
+Users:         s390-tools, HAL
+
+What:          /sys/bus/css/drivers/io_subchannel/.../pimpampom
+Date:          December 2002
+Contact:       Cornelia Huck <cornelia.huck@de.ibm.com>
+               linux-s390@vger.kernel.org
+Description:   Contains the PIM/PAM/POM values, as reported by the
+               channel subsystem when last queried by the common I/O
+               layer (this implies that this attribute is not neccessarily
+               in sync with the values current in the channel subsystem).
+               Note: This is an I/O-subchannel specific attribute.
+Users:         s390-tools, HAL
diff --git a/Documentation/ABI/testing/sysfs-firmware-memmap b/Documentation/ABI/testing/sysfs-firmware-memmap
new file mode 100644 (file)
index 0000000..0d99ee6
--- /dev/null
@@ -0,0 +1,71 @@
+What:          /sys/firmware/memmap/
+Date:          June 2008
+Contact:       Bernhard Walle <bwalle@suse.de>
+Description:
+               On all platforms, the firmware provides a memory map which the
+               kernel reads. The resources from that memory map are registered
+               in the kernel resource tree and exposed to userspace via
+               /proc/iomem (together with other resources).
+
+               However, on most architectures that firmware-provided memory
+               map is modified afterwards by the kernel itself, either because
+               the kernel merges that memory map with other information or
+               just because the user overwrites that memory map via command
+               line.
+
+               kexec needs the raw firmware-provided memory map to setup the
+               parameter segment of the kernel that should be booted with
+               kexec. Also, the raw memory map is useful for debugging. For
+               that reason, /sys/firmware/memmap is an interface that provides
+               the raw memory map to userspace.
+
+               The structure is as follows: Under /sys/firmware/memmap there
+               are subdirectories with the number of the entry as their name:
+
+                       /sys/firmware/memmap/0
+                       /sys/firmware/memmap/1
+                       /sys/firmware/memmap/2
+                       /sys/firmware/memmap/3
+                       ...
+
+               The maximum depends on the number of memory map entries provided
+               by the firmware. The order is just the order that the firmware
+               provides.
+
+               Each directory contains three files:
+
+               start   : The start address (as hexadecimal number with the
+                         '0x' prefix).
+               end     : The end address, inclusive (regardless whether the
+                         firmware provides inclusive or exclusive ranges).
+               type    : Type of the entry as string. See below for a list of
+                         valid types.
+
+               So, for example:
+
+                       /sys/firmware/memmap/0/start
+                       /sys/firmware/memmap/0/end
+                       /sys/firmware/memmap/0/type
+                       /sys/firmware/memmap/1/start
+                       ...
+
+               Currently following types exist:
+
+                 - System RAM
+                 - ACPI Tables
+                 - ACPI Non-volatile Storage
+                 - reserved
+
+               Following shell snippet can be used to display that memory
+               map in a human-readable format:
+
+               -------------------- 8< ----------------------------------------
+                 #!/bin/bash
+                 cd /sys/firmware/memmap
+                 for dir in * ; do
+                     start=$(cat $dir/start)
+                     end=$(cat $dir/end)
+                     type=$(cat $dir/type)
+                     printf "%016x-%016x (%s)\n" $start $[ $end +1] "$type"
+                 done
+               -------------------- >8 ----------------------------------------
diff --git a/Documentation/block/data-integrity.txt b/Documentation/block/data-integrity.txt
new file mode 100644 (file)
index 0000000..e9dc8d8
--- /dev/null
@@ -0,0 +1,327 @@
+----------------------------------------------------------------------
+1. INTRODUCTION
+
+Modern filesystems feature checksumming of data and metadata to
+protect against data corruption.  However, the detection of the
+corruption is done at read time which could potentially be months
+after the data was written.  At that point the original data that the
+application tried to write is most likely lost.
+
+The solution is to ensure that the disk is actually storing what the
+application meant it to.  Recent additions to both the SCSI family
+protocols (SBC Data Integrity Field, SCC protection proposal) as well
+as SATA/T13 (External Path Protection) try to remedy this by adding
+support for appending integrity metadata to an I/O.  The integrity
+metadata (or protection information in SCSI terminology) includes a
+checksum for each sector as well as an incrementing counter that
+ensures the individual sectors are written in the right order.  And
+for some protection schemes also that the I/O is written to the right
+place on disk.
+
+Current storage controllers and devices implement various protective
+measures, for instance checksumming and scrubbing.  But these
+technologies are working in their own isolated domains or at best
+between adjacent nodes in the I/O path.  The interesting thing about
+DIF and the other integrity extensions is that the protection format
+is well defined and every node in the I/O path can verify the
+integrity of the I/O and reject it if corruption is detected.  This
+allows not only corruption prevention but also isolation of the point
+of failure.
+
+----------------------------------------------------------------------
+2. THE DATA INTEGRITY EXTENSIONS
+
+As written, the protocol extensions only protect the path between
+controller and storage device.  However, many controllers actually
+allow the operating system to interact with the integrity metadata
+(IMD).  We have been working with several FC/SAS HBA vendors to enable
+the protection information to be transferred to and from their
+controllers.
+
+The SCSI Data Integrity Field works by appending 8 bytes of protection
+information to each sector.  The data + integrity metadata is stored
+in 520 byte sectors on disk.  Data + IMD are interleaved when
+transferred between the controller and target.  The T13 proposal is
+similar.
+
+Because it is highly inconvenient for operating systems to deal with
+520 (and 4104) byte sectors, we approached several HBA vendors and
+encouraged them to allow separation of the data and integrity metadata
+scatter-gather lists.
+
+The controller will interleave the buffers on write and split them on
+read.  This means that the Linux can DMA the data buffers to and from
+host memory without changes to the page cache.
+
+Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs
+is somewhat heavy to compute in software.  Benchmarks found that
+calculating this checksum had a significant impact on system
+performance for a number of workloads.  Some controllers allow a
+lighter-weight checksum to be used when interfacing with the operating
+system.  Emulex, for instance, supports the TCP/IP checksum instead.
+The IP checksum received from the OS is converted to the 16-bit CRC
+when writing and vice versa.  This allows the integrity metadata to be
+generated by Linux or the application at very low cost (comparable to
+software RAID5).
+
+The IP checksum is weaker than the CRC in terms of detecting bit
+errors.  However, the strength is really in the separation of the data
+buffers and the integrity metadata.  These two distinct buffers much
+match up for an I/O to complete.
+
+The separation of the data and integrity metadata buffers as well as
+the choice in checksums is referred to as the Data Integrity
+Extensions.  As these extensions are outside the scope of the protocol
+bodies (T10, T13), Oracle and its partners are trying to standardize
+them within the Storage Networking Industry Association.
+
+----------------------------------------------------------------------
+3. KERNEL CHANGES
+
+The data integrity framework in Linux enables protection information
+to be pinned to I/Os and sent to/received from controllers that
+support it.
+
+The advantage to the integrity extensions in SCSI and SATA is that
+they enable us to protect the entire path from application to storage
+device.  However, at the same time this is also the biggest
+disadvantage. It means that the protection information must be in a
+format that can be understood by the disk.
+
+Generally Linux/POSIX applications are agnostic to the intricacies of
+the storage devices they are accessing.  The virtual filesystem switch
+and the block layer make things like hardware sector size and
+transport protocols completely transparent to the application.
+
+However, this level of detail is required when preparing the
+protection information to send to a disk.  Consequently, the very
+concept of an end-to-end protection scheme is a layering violation.
+It is completely unreasonable for an application to be aware whether
+it is accessing a SCSI or SATA disk.
+
+The data integrity support implemented in Linux attempts to hide this
+from the application.  As far as the application (and to some extent
+the kernel) is concerned, the integrity metadata is opaque information
+that's attached to the I/O.
+
+The current implementation allows the block layer to automatically
+generate the protection information for any I/O.  Eventually the
+intent is to move the integrity metadata calculation to userspace for
+user data.  Metadata and other I/O that originates within the kernel
+will still use the automatic generation interface.
+
+Some storage devices allow each hardware sector to be tagged with a
+16-bit value.  The owner of this tag space is the owner of the block
+device.  I.e. the filesystem in most cases.  The filesystem can use
+this extra space to tag sectors as they see fit.  Because the tag
+space is limited, the block interface allows tagging bigger chunks by
+way of interleaving.  This way, 8*16 bits of information can be
+attached to a typical 4KB filesystem block.
+
+This also means that applications such as fsck and mkfs will need
+access to manipulate the tags from user space.  A passthrough
+interface for this is being worked on.
+
+
+----------------------------------------------------------------------
+4. BLOCK LAYER IMPLEMENTATION DETAILS
+
+4.1 BIO
+
+The data integrity patches add a new field to struct bio when
+CONFIG_BLK_DEV_INTEGRITY is enabled.  bio->bi_integrity is a pointer
+to a struct bip which contains the bio integrity payload.  Essentially
+a bip is a trimmed down struct bio which holds a bio_vec containing
+the integrity metadata and the required housekeeping information (bvec
+pool, vector count, etc.)
+
+A kernel subsystem can enable data integrity protection on a bio by
+calling bio_integrity_alloc(bio).  This will allocate and attach the
+bip to the bio.
+
+Individual pages containing integrity metadata can subsequently be
+attached using bio_integrity_add_page().
+
+bio_free() will automatically free the bip.
+
+
+4.2 BLOCK DEVICE
+
+Because the format of the protection data is tied to the physical
+disk, each block device has been extended with a block integrity
+profile (struct blk_integrity).  This optional profile is registered
+with the block layer using blk_integrity_register().
+
+The profile contains callback functions for generating and verifying
+the protection data, as well as getting and setting application tags.
+The profile also contains a few constants to aid in completing,
+merging and splitting the integrity metadata.
+
+Layered block devices will need to pick a profile that's appropriate
+for all subdevices.  blk_integrity_compare() can help with that.  DM
+and MD linear, RAID0 and RAID1 are currently supported.  RAID4/5/6
+will require extra work due to the application tag.
+
+
+----------------------------------------------------------------------
+5.0 BLOCK LAYER INTEGRITY API
+
+5.1 NORMAL FILESYSTEM
+
+    The normal filesystem is unaware that the underlying block device
+    is capable of sending/receiving integrity metadata.  The IMD will
+    be automatically generated by the block layer at submit_bio() time
+    in case of a WRITE.  A READ request will cause the I/O integrity
+    to be verified upon completion.
+
+    IMD generation and verification can be toggled using the
+
+      /sys/block/<bdev>/integrity/write_generate
+
+    and
+
+      /sys/block/<bdev>/integrity/read_verify
+
+    flags.
+
+
+5.2 INTEGRITY-AWARE FILESYSTEM
+
+    A filesystem that is integrity-aware can prepare I/Os with IMD
+    attached.  It can also use the application tag space if this is
+    supported by the block device.
+
+
+    int bdev_integrity_enabled(block_device, int rw);
+
+      bdev_integrity_enabled() will return 1 if the block device
+      supports integrity metadata transfer for the data direction
+      specified in 'rw'.
+
+      bdev_integrity_enabled() honors the write_generate and
+      read_verify flags in sysfs and will respond accordingly.
+
+
+    int bio_integrity_prep(bio);
+
+      To generate IMD for WRITE and to set up buffers for READ, the
+      filesystem must call bio_integrity_prep(bio).
+
+      Prior to calling this function, the bio data direction and start
+      sector must be set, and the bio should have all data pages
+      added.  It is up to the caller to ensure that the bio does not
+      change while I/O is in progress.
+
+      bio_integrity_prep() should only be called if
+      bio_integrity_enabled() returned 1.
+
+
+    int bio_integrity_tag_size(bio);
+
+      If the filesystem wants to use the application tag space it will
+      first have to find out how much storage space is available.
+      Because tag space is generally limited (usually 2 bytes per
+      sector regardless of sector size), the integrity framework
+      supports interleaving the information between the sectors in an
+      I/O.
+
+      Filesystems can call bio_integrity_tag_size(bio) to find out how
+      many bytes of storage are available for that particular bio.
+
+      Another option is bdev_get_tag_size(block_device) which will
+      return the number of available bytes per hardware sector.
+
+
+    int bio_integrity_set_tag(bio, void *tag_buf, len);
+
+      After a successful return from bio_integrity_prep(),
+      bio_integrity_set_tag() can be used to attach an opaque tag
+      buffer to a bio.  Obviously this only makes sense if the I/O is
+      a WRITE.
+
+
+    int bio_integrity_get_tag(bio, void *tag_buf, len);
+
+      Similarly, at READ I/O completion time the filesystem can
+      retrieve the tag buffer using bio_integrity_get_tag().
+
+
+6.3 PASSING EXISTING INTEGRITY METADATA
+
+    Filesystems that either generate their own integrity metadata or
+    are capable of transferring IMD from user space can use the
+    following calls:
+
+
+    struct bip * bio_integrity_alloc(bio, gfp_mask, nr_pages);
+
+      Allocates the bio integrity payload and hangs it off of the bio.
+      nr_pages indicate how many pages of protection data need to be
+      stored in the integrity bio_vec list (similar to bio_alloc()).
+
+      The integrity payload will be freed at bio_free() time.
+
+
+    int bio_integrity_add_page(bio, page, len, offset);
+
+      Attaches a page containing integrity metadata to an existing
+      bio.  The bio must have an existing bip,
+      i.e. bio_integrity_alloc() must have been called.  For a WRITE,
+      the integrity metadata in the pages must be in a format
+      understood by the target device with the notable exception that
+      the sector numbers will be remapped as the request traverses the
+      I/O stack.  This implies that the pages added using this call
+      will be modified during I/O!  The first reference tag in the
+      integrity metadata must have a value of bip->bip_sector.
+
+      Pages can be added using bio_integrity_add_page() as long as
+      there is room in the bip bio_vec array (nr_pages).
+
+      Upon completion of a READ operation, the attached pages will
+      contain the integrity metadata received from the storage device.
+      It is up to the receiver to process them and verify data
+      integrity upon completion.
+
+
+6.4 REGISTERING A BLOCK DEVICE AS CAPABLE OF EXCHANGING INTEGRITY
+    METADATA
+
+    To enable integrity exchange on a block device the gendisk must be
+    registered as capable:
+
+    int blk_integrity_register(gendisk, blk_integrity);
+
+      The blk_integrity struct is a template and should contain the
+      following:
+
+        static struct blk_integrity my_profile = {
+            .name                   = "STANDARDSBODY-TYPE-VARIANT-CSUM",
+            .generate_fn            = my_generate_fn,
+                   .verify_fn              = my_verify_fn,
+                   .get_tag_fn             = my_get_tag_fn,
+                   .set_tag_fn             = my_set_tag_fn,
+           .tuple_size             = sizeof(struct my_tuple_size),
+           .tag_size               = <tag bytes per hw sector>,
+        };
+
+      'name' is a text string which will be visible in sysfs.  This is
+      part of the userland API so chose it carefully and never change
+      it.  The format is standards body-type-variant.
+      E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC.
+
+      'generate_fn' generates appropriate integrity metadata (for WRITE).
+
+      'verify_fn' verifies that the data buffer matches the integrity
+      metadata.
+
+      'tuple_size' must be set to match the size of the integrity
+      metadata per sector.  I.e. 8 for DIF and EPP.
+
+      'tag_size' must be set to identify how many bytes of tag space
+      are available per hardware sector.  For DIF this is either 2 or
+      0 depending on the value of the Control Mode Page ATO bit.
+
+      See 6.2 for a description of get_tag_fn and set_tag_fn.
+
+----------------------------------------------------------------------
+2007-12-24 Martin K. Petersen <martin.petersen@oracle.com>
index 240ce7a56c40c9edfd141468ef2f2f1cf40dfab5..3bb5f466a90db3e971b42fb26c60d716a30878ed 100644 (file)
@@ -117,6 +117,7 @@ Code        Seq#    Include File            Comments
                                        <mailto:natalia@nikhefk.nikhef.nl>
 'c'    00-7F   linux/comstats.h        conflict!
 'c'    00-7F   linux/coda.h            conflict!
+'c'    80-9F   asm-s390/chsc.h
 'd'    00-FF   linux/char/drm/drm/h    conflict!
 'd'    00-DF   linux/video_decoder.h   conflict!
 'd'    F0-FF   linux/digi1.h
index b8e52c0355d3bab81760adbf62d0c8a06a9ba52a..9691c7f5166c1ea60acfbc383799dc5ec4dcbd21 100644 (file)
@@ -109,7 +109,7 @@ There are two possible methods of using Kdump.
 2) Or use the system kernel binary itself as dump-capture kernel and there is
    no need to build a separate dump-capture kernel. This is possible
    only with the architecutres which support a relocatable kernel. As
-   of today i386 and ia64 architectures support relocatable kernel.
+   of today, i386, x86_64 and ia64 architectures support relocatable kernel.
 
 Building a relocatable kernel is advantageous from the point of view that
 one does not have to build a second kernel for capturing the dump. But
index b52f47d588b40fea417bf4bca4ffdbfef4d02152..795c487af8e4dbbcdb0cedf5d048e7036bbb5ee0 100644 (file)
@@ -271,6 +271,17 @@ and is between 256 and 4096 characters. It is defined in the file
        aic79xx=        [HW,SCSI]
                        See Documentation/scsi/aic79xx.txt.
 
+       amd_iommu=      [HW,X86-84]
+                       Pass parameters to the AMD IOMMU driver in the system.
+                       Possible values are:
+                       isolate - enable device isolation (each device, as far
+                                 as possible, will get its own protection
+                                 domain)
+       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>
@@ -599,6 +610,29 @@ and is between 256 and 4096 characters. It is defined in the file
                        See drivers/char/README.epca and
                        Documentation/digiepca.txt.
 
+       disable_mtrr_cleanup [X86]
+       enable_mtrr_cleanup [X86]
+                       The kernel tries to adjust MTRR layout from continuous
+                       to discrete, to make X server driver able to add WB
+                       entry later. This parameter enables/disables that.
+
+       mtrr_chunk_size=nn[KMG] [X86]
+                       used for mtrr cleanup. It is largest continous chunk
+                       that could hold holes aka. UC entries.
+
+       mtrr_gran_size=nn[KMG] [X86]
+                       Used for mtrr cleanup. It is granularity of mtrr block.
+                       Default is 1.
+                       Large value could prevent small alignment from
+                       using up MTRRs.
+
+       mtrr_spare_reg_nr=n [X86]
+                       Format: <integer>
+                       Range: 0,7 : spare reg number
+                       Default : 1
+                       Used for mtrr cleanup. It is spare mtrr entries number.
+                       Set to 2 or more if your graphical card needs more.
+
        disable_mtrr_trim [X86, Intel and AMD only]
                        By default the kernel will trim any uncacheable
                        memory out of your available memory pool based on
@@ -2116,6 +2150,9 @@ and is between 256 and 4096 characters. It is defined in the file
        usbhid.mousepoll=
                        [USBHID] The interval which mice are to be polled at.
 
+       add_efi_memmap  [EFI; x86-32,X86-64] Include EFI memory map in
+                       kernel's map of available physical RAM.
+
        vdso=           [X86-32,SH,x86-64]
                        vdso=2: enable compat VDSO (default with COMPAT_VDSO)
                        vdso=1: enable VDSO (default)
index 757c729ee42e717f8908ec148c9221948164ade1..90aa4531cb67343b03b396610aa0db77c1d1e0ba 100644 (file)
@@ -10,7 +10,7 @@ us to generate 'watchdog NMI interrupts'.  (NMI: Non Maskable Interrupt
 which get executed even if the system is otherwise locked up hard).
 This can be used to debug hard kernel lockups.  By executing periodic
 NMI interrupts, the kernel can monitor whether any CPU has locked up,
-and print out debugging messages if so.  
+and print out debugging messages if so.
 
 In order to use the NMI watchdog, you need to have APIC support in your
 kernel. For SMP kernels, APIC support gets compiled in automatically. For
@@ -22,8 +22,7 @@ CONFIG_X86_UP_IOAPIC is for uniprocessor with an IO-APIC. [Note: certain
 kernel debugging options, such as Kernel Stack Meter or Kernel Tracer,
 may implicitly disable the NMI watchdog.]
 
-For x86-64, the needed APIC is always compiled in, and the NMI watchdog is
-always enabled with I/O-APIC mode (nmi_watchdog=1).
+For x86-64, the needed APIC is always compiled in.
 
 Using local APIC (nmi_watchdog=2) needs the first performance register, so
 you can't use it for other purposes (such as high precision performance
@@ -63,16 +62,15 @@ when the system is idle), but if your system locks up on anything but the
 "hlt", then you are out of luck -- the event will not happen at all and the
 watchdog won't trigger. This is a shortcoming of the local APIC watchdog
 -- unfortunately there is no "clock ticks" event that would work all the
-time. The I/O APIC watchdog is driven externally and has no such shortcoming.  
+time. The I/O APIC watchdog is driven externally and has no such shortcoming.
 But its NMI frequency is much higher, resulting in a more significant hit
 to the overall system performance.
 
-NOTE: starting with 2.4.2-ac18 the NMI-oopser is disabled by default,
-you have to enable it with a boot time parameter.  Prior to 2.4.2-ac18
-the NMI-oopser is enabled unconditionally on x86 SMP boxes.
+On x86 nmi_watchdog is disabled by default so you have to enable it with
+a boot time parameter.
 
-On x86-64 the NMI oopser is on by default. On 64bit Intel CPUs
-it uses IO-APIC by default and on AMD it uses local APIC.
+NOTE: In kernels prior to 2.4.2-ac18 the NMI-oopser is enabled unconditionally
+on x86 SMP boxes.
 
 [ feel free to send bug reports, suggestions and patches to
   Ingo Molnar <mingo@redhat.com> or the Linux SMP mailing
index 0bbee38acd263f6e88605ac71e3bd12c8ca3bf70..72aff61e731509d7c87f3a3913aa3b4e965ab9c5 100644 (file)
@@ -753,8 +753,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     [Multiple options for each card instance]
     model      - force the model name
-    position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+    position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF)
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
+    bdl_pos_adj        - Specifies the DMA IRQ timing delay in samples.
+               Passing -1 will make the driver to choose the appropriate
+               value based on the controller chip.
     
     [Single (global) options]
     single_cmd  - Use single immediate commands to communicate with
@@ -845,7 +848,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
        ALC269
          basic         Basic preset
 
-       ALC662
+       ALC662/663
          3stack-dig    3-stack (2-channel) with SPDIF
          3stack-6ch     3-stack (6-channel)
          3stack-6ch-dig 3-stack (6-channel) with SPDIF
@@ -853,6 +856,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          lenovo-101e    Lenovo laptop
          eeepc-p701    ASUS Eeepc P701
          eeepc-ep20    ASUS Eeepc EP20
+         m51va         ASUS M51VA
+         g71v          ASUS G71V
+         h13           ASUS H13
+         g50v          ASUS G50V
          auto          auto-config reading BIOS (default)
 
        ALC882/885
@@ -1091,7 +1098,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     This occurs when the access to non-existing or non-working codec slot
     (likely a modem one) causes a stall of the communication via HD-audio
     bus.  You can see which codec slots are probed by enabling
-    CONFIG_SND_DEBUG_DETECT, or simply from the file name of the codec
+    CONFIG_SND_DEBUG_VERBOSE, or simply from the file name of the codec
     proc files.  Then limit the slots to probe by probe_mask option.
     For example, probe_mask=1 means to probe only the first slot, and
     probe_mask=4 means only the third slot.
@@ -2267,6 +2274,10 @@ case above again, the first two slots are already reserved.  If any
 other driver (e.g. snd-usb-audio) is loaded before snd-interwave or
 snd-ens1371, it will be assigned to the third or later slot.
 
+When a module name is given with '!', the slot will be given for any
+modules but that name.  For example, "slots=!snd-pcsp" will reserve
+the first slot for any modules but snd-pcsp. 
+
 
 ALSA PCM devices to OSS devices mapping
 =======================================
index b03df4d4795c6767b79bed4125b07bbdf64fc823..e13c4e67029f497899d4cbc545f67fd073d36e1f 100644 (file)
@@ -6127,8 +6127,8 @@ struct _snd_pcm_runtime {
 
       <para>
         <function>snd_printdd()</function> is compiled in only when
-      <constant>CONFIG_SND_DEBUG_DETECT</constant> is set. Please note
-      that <constant>DEBUG_DETECT</constant> is not set as default
+      <constant>CONFIG_SND_DEBUG_VERBOSE</constant> is set. Please note
+      that <constant>CONFIG_SND_DEBUG_VERBOSE</constant> is not set as default
       even if you configure the alsa-driver with
       <option>--with-debug=full</option> option. You need to give
       explicitly <option>--with-debug=detect</option> option instead. 
similarity index 96%
rename from Documentation/i386/boot.txt
rename to Documentation/x86/i386/boot.txt
index 95ad15c3b01f3256b8f06efb6a1a5f3905d02952..147bfe511cdda0d923ca1094a27daac02225af53 100644 (file)
@@ -1,17 +1,14 @@
-                    THE LINUX/I386 BOOT PROTOCOL
-                    ----------------------------
+                    THE LINUX/x86 BOOT PROTOCOL
+                    ---------------------------
 
-                   H. Peter Anvin <hpa@zytor.com>
-                       Last update 2007-05-23
-
-On the i386 platform, the Linux kernel uses a rather complicated boot
+On the x86 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
 well as the desire in the early days to have the kernel itself be a
 bootable image, the complicated PC memory model and due to changed
 expectations in the PC industry caused by the effective demise of
 real-mode DOS as a mainstream operating system.
 
-Currently, the following versions of the Linux/i386 boot protocol exist.
+Currently, the following versions of the Linux/x86 boot protocol exist.
 
 Old kernels:   zImage/Image support only.  Some very early kernels
                may not even support a command line.
@@ -372,10 +369,17 @@ Protocol: 2.00+
        - If 0, the protected-mode code is loaded at 0x10000.
        - If 1, the protected-mode code is loaded at 0x100000.
 
+  Bit 5 (write): QUIET_FLAG
+       - If 0, print early messages.
+       - If 1, suppress early messages.
+               This requests to the kernel (decompressor and early
+               kernel) to not write early messages that require
+               accessing the display hardware directly.
+
   Bit 6 (write): KEEP_SEGMENTS
        Protocol: 2.07+
-       - if 0, reload the segment registers in the 32bit entry point.
-       - if 1, do not reload the segment registers in the 32bit entry point.
+       - If 0, reload the segment registers in the 32bit entry point.
+       - If 1, do not reload the segment registers in the 32bit entry point.
                Assume that %cs %ds %ss %es are all set to flat segments with
                a base of 0 (or the equivalent for their environment).
 
@@ -504,7 +508,7 @@ Protocol:   2.06+
   maximum size was 255.
 
 Field name:    hardware_subarch
-Type:          write
+Type:          write (optional, defaults to x86/PC)
 Offset/size:   0x23c/4
 Protocol:      2.07+
 
@@ -520,11 +524,13 @@ Protocol: 2.07+
   0x00000002   Xen
 
 Field name:    hardware_subarch_data
-Type:          write
+Type:          write (subarch-dependent)
 Offset/size:   0x240/8
 Protocol:      2.07+
 
   A pointer to data that is specific to hardware subarch
+  This field is currently unused for the default x86/PC environment,
+  do not modify.
 
 Field name:    payload_offset
 Type:          read
@@ -545,6 +551,34 @@ Protocol:  2.08+
 
   The length of the payload.
 
+Field name:    setup_data
+Type:          write (special)
+Offset/size:   0x250/8
+Protocol:      2.09+
+
+  The 64-bit physical pointer to NULL terminated single linked list of
+  struct setup_data. This is used to define a more extensible boot
+  parameters passing mechanism. The definition of struct setup_data is
+  as follow:
+
+  struct setup_data {
+         u64 next;
+         u32 type;
+         u32 len;
+         u8  data[0];
+  };
+
+  Where, the next is a 64-bit physical pointer to the next node of
+  linked list, the next field of the last node is 0; the type is used
+  to identify the contents of data; the len is the length of data
+  field; the data holds the real payload.
+
+  This list may be modified at a number of points during the bootup
+  process.  Therefore, when modifying this list one should always make
+  sure to consider the case where the linked list already contains
+  entries.
+
+
 **** THE IMAGE CHECKSUM
 
 From boot protocol version 2.08 onwards the CRC-32 is calculated over
@@ -553,6 +587,7 @@ initial remainder of 0xffffffff.  The checksum is appended to the
 file; therefore the CRC of the file up to the limit specified in the
 syssize field of the header is always 0.
 
+
 **** THE KERNEL COMMAND LINE
 
 The kernel command line has become an important way for the boot
@@ -584,28 +619,6 @@ command line is entered using the following protocol:
        covered by setup_move_size, so you may need to adjust this
        field.
 
-Field name:    setup_data
-Type:          write (obligatory)
-Offset/size:   0x250/8
-Protocol:      2.09+
-
-  The 64-bit physical pointer to NULL terminated single linked list of
-  struct setup_data. This is used to define a more extensible boot
-  parameters passing mechanism. The definition of struct setup_data is
-  as follow:
-
-  struct setup_data {
-         u64 next;
-         u32 type;
-         u32 len;
-         u8  data[0];
-  };
-
-  Where, the next is a 64-bit physical pointer to the next node of
-  linked list, the next field of the last node is 0; the type is used
-  to identify the contents of data; the len is the length of data
-  field; the data holds the real payload.
-
 
 **** MEMORY LAYOUT OF THE REAL-MODE CODE
 
similarity index 87%
rename from Documentation/x86_64/mm.txt
rename to Documentation/x86/x86_64/mm.txt
index b89b6d2bebfa7b355aeffacc5c7e60e91eb54a86..efce7509736911434e299d0fe63e344c70d7b1e3 100644 (file)
@@ -11,9 +11,8 @@ ffffc10000000000 - ffffc1ffffffffff (=40 bits) hole
 ffffc20000000000 - ffffe1ffffffffff (=45 bits) vmalloc/ioremap space
 ffffe20000000000 - ffffe2ffffffffff (=40 bits) virtual memory map (1TB)
 ... unused hole ...
-ffffffff80000000 - ffffffff82800000 (=40 MB)   kernel text mapping, from phys 0
-... unused hole ...
-ffffffff88000000 - fffffffffff00000 (=1919 MB) module mapping space
+ffffffff80000000 - ffffffffa0000000 (=512 MB)  kernel text mapping, from phys 0
+ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space
 
 The direct mapping covers all memory in the system up to the highest
 memory address (this means in some cases it can also include PCI memory
similarity index 84%
rename from Documentation/x86_64/uefi.txt
rename to Documentation/x86/x86_64/uefi.txt
index 7d77120a51841aea77164a6aab2f682f10ca1a2d..a5e2b4fdb17049106f396a4bbc9f0bbff426cae3 100644 (file)
@@ -36,3 +36,7 @@ Mechanics:
   services.
        noefi           turn off all EFI runtime services
        reboot_type=k   turn off EFI reboot runtime service
+- If the EFI memory map has additional entries not in the E820 map,
+  you can include those entries in the kernels memory map of available
+  physical RAM by using the following kernel command line parameter.
+       add_efi_memmap  include EFI memory map of available physical RAM
index 56a2f678019e7c067e62ce7a95c1fb86ade5df2d..1528e58b540829a110eba85ad8bd0e5bea4a4c41 100644 (file)
@@ -376,6 +376,12 @@ L: linux-geode@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html
 S:     Supported
 
+AMD IOMMU (AMD-VI)
+P:     Joerg Roedel
+M:     joerg.roedel@amd.com
+L:     iommu@lists.linux-foundation.org
+S:     Supported
+
 AMS (Apple Motion Sensor) DRIVER
 P:     Stelian Pop
 M:     stelian@popies.net
index 09ad7995080c879cc4b944cf671484ac24746830..45d63c9860150fd70d566b8a032ccebda568f954 100644 (file)
@@ -88,6 +88,7 @@ config PLATFORM_AT32AP
        select MMU
        select PERFORMANCE_COUNTERS
        select HAVE_GPIO_LIB
+       select GENERIC_ALLOCATOR
 
 #
 # CPU types
@@ -147,6 +148,9 @@ config PHYS_OFFSET
 
 source "kernel/Kconfig.preempt"
 
+config QUICKLIST
+       def_bool y
+
 config HAVE_ARCH_BOOTMEM_NODE
        def_bool n
 
@@ -201,6 +205,11 @@ endmenu
 
 menu "Power management options"
 
+source "kernel/power/Kconfig"
+
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+
 menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
index a398be2849666bf974696ba383800df885ee3cf7..a51bb9fb3c89d2047151a5da22d14c7582a43643 100644 (file)
@@ -9,6 +9,8 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/arch/init.h>
 #include <asm/arch/portmux.h>
 
+/* Oscillator frequencies. These are board-specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
+
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
 
@@ -140,6 +149,10 @@ static struct platform_device i2c_gpio_device = {
        },
 };
 
+static struct i2c_board_info __initdata i2c_info[] = {
+       /* NOTE:  original ATtiny24 firmware is at address 0x0b */
+};
+
 static int __init atngw100_init(void)
 {
        unsigned        i;
@@ -165,12 +178,28 @@ static int __init atngw100_init(void)
        }
        platform_device_register(&ngw_gpio_leds);
 
+       /* all these i2c/smbus pins should have external pullups for
+        * open-drain sharing among all I2C devices.  SDA and SCL do;
+        * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
+        * but it's not available off-board.
+        */
+       at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
        at32_select_gpio(i2c_gpio_data.sda_pin,
                AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
        at32_select_gpio(i2c_gpio_data.scl_pin,
                AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
        platform_device_register(&i2c_gpio_device);
+       i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 
        return 0;
 }
 postcore_initcall(atngw100_init);
+
+static int __init atngw100_arch_init(void)
+{
+       /* set_irq_type() after the arch_initcall for EIC has run, and
+        * before the I2C subsystem could try using this IRQ.
+        */
+       return set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING);
+}
+arch_initcall(atngw100_arch_init);
index 000eb4220a12619b4e9b9922f5ed7d9e4c958064..86b363c1c25bea00dfe011425c044d6d91edd0f9 100644 (file)
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
 
 struct eth_addr {
        u8 addr[6];
@@ -232,7 +238,7 @@ static int __init atstk1002_init(void)
        set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size);
+                            fbmem_start, fbmem_size, 0);
 #endif
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
index a0b223df35a253ed1afa45106864dc47ade6b744..ea109f435a83adc6ffb67cd8264d8a84552f52c9 100644 (file)
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
        .ssc_id         = 0,
index e765a8652b3ee58480847302923170ed668150d3..c7236df74d7422125d6048c33804f8d167c1c91c 100644 (file)
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
        .ssc_id         = 0,
@@ -133,7 +140,7 @@ static int __init atstk1004_init(void)
        at32_add_device_mci(0);
 #endif
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size);
+                            fbmem_start, fbmem_size, 0);
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
        at32_add_device_ssc(0, ATMEL_SSC_TX);
index 5f31702d6b1c9e3ffc55ee4866b8ac4f7b2dfdcb..2b398cae110c839fc5b3c3be3d9d7a48fcf3a2ec 100644 (file)
@@ -74,50 +74,41 @@ exception_vectors:
        .align  2
        bral    do_dtlb_modified
 
-       /*
-        * r0 : PGD/PT/PTE
-        * r1 : Offending address
-        * r2 : Scratch register
-        * r3 : Cause (5, 12 or 13)
-        */
 #define        tlbmiss_save    pushm   r0-r3
 #define tlbmiss_restore        popm    r0-r3
 
-       .section .tlbx.ex.text,"ax",@progbits
+       .org    0x50
        .global itlb_miss
 itlb_miss:
        tlbmiss_save
        rjmp    tlb_miss_common
 
-       .section .tlbr.ex.text,"ax",@progbits
+       .org    0x60
 dtlb_miss_read:
        tlbmiss_save
        rjmp    tlb_miss_common
 
-       .section .tlbw.ex.text,"ax",@progbits
+       .org    0x70
 dtlb_miss_write:
        tlbmiss_save
 
        .global tlb_miss_common
+       .align  2
 tlb_miss_common:
        mfsr    r0, SYSREG_TLBEAR
        mfsr    r1, SYSREG_PTBR
 
-       /* Is it the vmalloc space? */
-       bld     r0, 31
-       brcs    handle_vmalloc_miss
-
-       /* First level lookup */
+       /*
+        * First level lookup: The PGD contains virtual pointers to
+        * the second-level page tables, but they may be NULL if not
+        * present.
+        */
 pgtbl_lookup:
        lsr     r2, r0, PGDIR_SHIFT
        ld.w    r3, r1[r2 << 2]
        bfextu  r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
-       bld     r3, _PAGE_BIT_PRESENT
-       brcc    page_table_not_present
-
-       /* Translate to virtual address in P1. */
-       andl    r3, 0xf000
-       sbr     r3, 31
+       cp.w    r3, 0
+       breq    page_table_not_present
 
        /* Second level lookup */
        ld.w    r2, r3[r1 << 2]
@@ -148,16 +139,55 @@ pgtbl_lookup:
        tlbmiss_restore
        rete
 
-handle_vmalloc_miss:
-       /* Simply do the lookup in init's page table */
+       /* The slow path of the TLB miss handler */
+       .align  2
+page_table_not_present:
+       /* Do we need to synchronize with swapper_pg_dir? */
+       bld     r0, 31
+       brcs    sync_with_swapper_pg_dir
+
+page_not_present:
+       tlbmiss_restore
+       sub     sp, 4
+       stmts   --sp, r0-lr
+       rcall   save_full_context_ex
+       mfsr    r12, SYSREG_ECR
+       mov     r11, sp
+       rcall   do_page_fault
+       rjmp    ret_from_exception
+
+       .align  2
+sync_with_swapper_pg_dir:
+       /*
+        * If swapper_pg_dir contains a non-NULL second-level page
+        * table pointer, copy it into the current PGD. If not, we
+        * must handle it as a full-blown page fault.
+        *
+        * Jumping back to pgtbl_lookup causes an unnecessary lookup,
+        * but it is guaranteed to be a cache hit, it won't happen
+        * very often, and we absolutely do not want to sacrifice any
+        * performance in the fast path in order to improve this.
+        */
        mov     r1, lo(swapper_pg_dir)
        orh     r1, hi(swapper_pg_dir)
+       ld.w    r3, r1[r2 << 2]
+       cp.w    r3, 0
+       breq    page_not_present
+       mfsr    r1, SYSREG_PTBR
+       st.w    r1[r2 << 2], r3
        rjmp    pgtbl_lookup
 
+       /*
+        * We currently have two bytes left at this point until we
+        * crash into the system call handler...
+        *
+        * Don't worry, the assembler will let us know.
+        */
+
 
        /* ---                    System Call                    --- */
 
-       .section .scall.text,"ax",@progbits
+       .org    0x100
 system_call:
 #ifdef CONFIG_PREEMPT
        mask_interrupts
@@ -266,18 +296,6 @@ syscall_exit_work:
        brcc    syscall_exit_cont
        rjmp    enter_monitor_mode
 
-       /* The slow path of the TLB miss handler */
-page_table_not_present:
-page_not_present:
-       tlbmiss_restore
-       sub     sp, 4
-       stmts   --sp, r0-lr
-       rcall   save_full_context_ex
-       mfsr    r12, SYSREG_ECR
-       mov     r11, sp
-       rcall   do_page_fault
-       rjmp    ret_from_exception
-
        /* This function expects to find offending PC in SYSREG_RAR_EX */
        .type   save_full_context_ex, @function
        .align  2
index 5616a00c10ba2f3a9660b63a25e57d021c00da92..c5b11f9067f104bf7dafca6e3bbb1ac89a38bc4f 100644 (file)
@@ -93,6 +93,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
 
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+               goto badframe;
+
        pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
                 regs->pc, regs->lr, regs->sp);
 
index 00a9862380ff3e10e3fc0dd73137197ad1982fe0..abd954fb7ba0ccbf37b1494b93c1600045fd1a88 100644 (file)
@@ -7,21 +7,13 @@
  */
 #include <linux/clk.h>
 #include <linux/clockchips.h>
-#include <linux/time.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/profile.h>
-#include <linux/sysdev.h>
-#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
 
-#include <asm/div64.h>
 #include <asm/sysreg.h>
-#include <asm/io.h>
-#include <asm/sections.h>
 
 #include <asm/arch/pm.h>
 
index 481cfd40c0539e85297ed33366ec579041d95680..5d25d8eeb750fd148ddb1cefdd2dcdc4e8204e69 100644 (file)
@@ -68,14 +68,6 @@ SECTIONS
                _evba = .;
                _text = .;
                *(.ex.text)
-               . = 0x50;
-               *(.tlbx.ex.text)
-               . = 0x60;
-               *(.tlbr.ex.text)
-               . = 0x70;
-               *(.tlbw.ex.text)
-               . = 0x100;
-               *(.scall.text)
                *(.irq.text)
                KPROBES_TEXT
                TEXT_TEXT
@@ -107,6 +99,10 @@ SECTIONS
                 */
                *(.data.init_task)
 
+               /* Then, the page-aligned data */
+               . = ALIGN(PAGE_SIZE);
+               *(.data.page_aligned)
+
                /* Then, the cacheline aligned data */
                . = ALIGN(L1_CACHE_BYTES);
                *(.data.cacheline_aligned)
index 2be5da7ed26b7f0b42269f073dfcdb5f15ba788a..cb2d8694555964d90606838d450d95499d33da7a 100644 (file)
@@ -41,7 +41,7 @@ __raw_readsb:
 2:     sub     r10, -4
        reteq   r12
 
-3:     ld.uh   r8, r12[0]
+3:     ld.ub   r8, r12[0]
        sub     r10, 1
        st.b    r11++, r8
        brne    3b
index e89009439e4aebf043bf335561ba7b1f93e7d4db..d5018e2eed255232309f6de74358604a96856f91 100644 (file)
@@ -1,3 +1,8 @@
-obj-y                          += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
+obj-y                          += pdc.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP700X)   += at32ap700x.o pm-at32ap700x.o
 obj-$(CONFIG_CPU_FREQ_AT32AP)  += cpufreq.o
+obj-$(CONFIG_PM)               += pm.o
+
+ifeq ($(CONFIG_PM_DEBUG),y)
+CFLAGS_pm.o    += -DDEBUG
+endif
index 0f24b4f85c17c6022b4dccf624532ec7e4aeb7db..07b21b121eef995726a6e8a981f3c416497e997e 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
+#include <asm/arch/sram.h>
 
 #include <video/atmel_lcdc.h>
 
@@ -93,19 +94,12 @@ static struct clk devname##_##_name = {                             \
 
 static DEFINE_SPINLOCK(pm_lock);
 
-unsigned long at32ap7000_osc_rates[3] = {
-       [0] = 32768,
-       /* FIXME: these are ATSTK1002-specific */
-       [1] = 20000000,
-       [2] = 12000000,
-};
-
 static struct clk osc0;
 static struct clk osc1;
 
 static unsigned long osc_get_rate(struct clk *clk)
 {
-       return at32ap7000_osc_rates[clk->index];
+       return at32_board_osc_rates[clk->index];
 }
 
 static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
@@ -682,6 +676,14 @@ static struct clk hramc_clk = {
        .users          = 1,
        .index          = 3,
 };
+static struct clk sdramc_clk = {
+       .name           = "sdramc_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 14,
+};
 
 static struct resource smc0_resource[] = {
        PBMEM(0xfff03400),
@@ -840,6 +842,81 @@ void __init at32_add_system_devices(void)
        platform_device_register(&pio4_device);
 }
 
+/* --------------------------------------------------------------------
+ *  PSIF
+ * -------------------------------------------------------------------- */
+static struct resource atmel_psif0_resource[] __initdata = {
+       {
+               .start  = 0xffe03c00,
+               .end    = 0xffe03cff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(18),
+};
+static struct clk atmel_psif0_pclk = {
+       .name           = "pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 15,
+};
+
+static struct resource atmel_psif1_resource[] __initdata = {
+       {
+               .start  = 0xffe03d00,
+               .end    = 0xffe03dff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(18),
+};
+static struct clk atmel_psif1_pclk = {
+       .name           = "pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 15,
+};
+
+struct platform_device *__init at32_add_device_psif(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (!(id == 0 || id == 1))
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_psif", id);
+       if (!pdev)
+               return NULL;
+
+       switch (id) {
+       case 0:
+               if (platform_device_add_resources(pdev, atmel_psif0_resource,
+                                       ARRAY_SIZE(atmel_psif0_resource)))
+                       goto err_add_resources;
+               atmel_psif0_pclk.dev = &pdev->dev;
+               select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
+               select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+               break;
+       case 1:
+               if (platform_device_add_resources(pdev, atmel_psif1_resource,
+                                       ARRAY_SIZE(atmel_psif1_resource)))
+                       goto err_add_resources;
+               atmel_psif1_pclk.dev = &pdev->dev;
+               select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
+               select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+               break;
+       default:
+               return NULL;
+       }
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
 /* --------------------------------------------------------------------
  *  USART
  * -------------------------------------------------------------------- */
@@ -1113,7 +1190,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
        switch (id) {
        case 0:
                pdev = &atmel_spi0_device;
-               select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
+               /* pullup MISO so a level is always defined */
+               select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
                select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
                select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
                at32_spi_setup_slaves(0, b, n, spi0_pins);
@@ -1121,7 +1199,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
 
        case 1:
                pdev = &atmel_spi1_device;
-               select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
+               /* pullup MISO so a level is always defined */
+               select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
                select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
                select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
                at32_spi_setup_slaves(1, b, n, spi1_pins);
@@ -1264,7 +1343,8 @@ static struct clk atmel_lcdfb0_pixclk = {
 
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len)
+                    unsigned long fbmem_start, unsigned long fbmem_len,
+                    unsigned int pin_config)
 {
        struct platform_device *pdev;
        struct atmel_lcdfb_info *info;
@@ -1291,37 +1371,77 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
        switch (id) {
        case 0:
                pdev = &atmel_lcdfb0_device;
-               select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-               select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-               select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-               select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-               select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-               select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-               select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-               select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-               select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-               select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-               select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-               select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-               select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-               select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-               select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-               select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-               select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-               select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-               select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-               select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-               select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-               select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-               select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-               select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-               select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-               select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-               select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-               select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-               select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-               select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-               select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+
+               switch (pin_config) {
+               case 0:
+                       select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
+                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+                       select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
+                       select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
+                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+                       select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
+                       select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
+                       select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
+                       select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
+                       select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
+                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+                       select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
+                       select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
+                       select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
+                       select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
+                       select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
+                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+                       select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+                       select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+                       select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+                       select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+                       select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+                       select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+                       break;
+               case 1:
+                       select_peripheral(PE(0),  PERIPH_B, 0); /* CC     */
+                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+                       select_peripheral(PE(1),  PERIPH_B, 0); /* DVAL   */
+                       select_peripheral(PE(2),  PERIPH_B, 0); /* MODE   */
+                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+                       select_peripheral(PE(3),  PERIPH_B, 0); /* DATA0  */
+                       select_peripheral(PE(4),  PERIPH_B, 0); /* DATA1  */
+                       select_peripheral(PE(5),  PERIPH_B, 0); /* DATA2  */
+                       select_peripheral(PE(6),  PERIPH_B, 0); /* DATA3  */
+                       select_peripheral(PE(7),  PERIPH_B, 0); /* DATA4  */
+                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+                       select_peripheral(PE(8),  PERIPH_B, 0); /* DATA8  */
+                       select_peripheral(PE(9),  PERIPH_B, 0); /* DATA9  */
+                       select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
+                       select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
+                       select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
+                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+                       select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
+                       select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
+                       select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
+                       select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
+                       select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
+                       select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
+                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+                       break;
+               default:
+                       goto err_invalid_id;
+               }
 
                clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
                clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1360,7 +1480,7 @@ static struct resource atmel_pwm0_resource[] __initdata = {
        IRQ(24),
 };
 static struct clk atmel_pwm0_mck = {
-       .name           = "mck",
+       .name           = "pwm_clk",
        .parent         = &pbb_clk,
        .mode           = pbb_clk_mode,
        .get_rate       = pbb_clk_get_rate,
@@ -1887,6 +2007,7 @@ struct clk *at32_clock_list[] = {
        &hmatrix_clk,
        &ebi_clk,
        &hramc_clk,
+       &sdramc_clk,
        &smc0_pclk,
        &smc0_mck,
        &pdc_hclk,
@@ -1900,6 +2021,8 @@ struct clk *at32_clock_list[] = {
        &pio4_mck,
        &at32_tcb0_t0_clk,
        &at32_tcb1_t0_clk,
+       &atmel_psif0_pclk,
+       &atmel_psif1_pclk,
        &atmel_usart0_usart,
        &atmel_usart1_usart,
        &atmel_usart2_usart,
@@ -1935,16 +2058,7 @@ struct clk *at32_clock_list[] = {
 };
 unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
-void __init at32_portmux_init(void)
-{
-       at32_init_pio(&pio0_device);
-       at32_init_pio(&pio1_device);
-       at32_init_pio(&pio2_device);
-       at32_init_pio(&pio3_device);
-       at32_init_pio(&pio4_device);
-}
-
-void __init at32_clock_init(void)
+void __init setup_platform(void)
 {
        u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
        int i;
@@ -1999,4 +2113,36 @@ void __init at32_clock_init(void)
        pm_writel(HSB_MASK, hsb_mask);
        pm_writel(PBA_MASK, pba_mask);
        pm_writel(PBB_MASK, pbb_mask);
+
+       /* Initialize the port muxes */
+       at32_init_pio(&pio0_device);
+       at32_init_pio(&pio1_device);
+       at32_init_pio(&pio2_device);
+       at32_init_pio(&pio3_device);
+       at32_init_pio(&pio4_device);
+}
+
+struct gen_pool *sram_pool;
+
+static int __init sram_init(void)
+{
+       struct gen_pool *pool;
+
+       /* 1KiB granularity */
+       pool = gen_pool_create(10, -1);
+       if (!pool)
+               goto fail;
+
+       if (gen_pool_add(pool, 0x24000000, 0x8000, -1))
+               goto err_pool_add;
+
+       sram_pool = pool;
+       return 0;
+
+err_pool_add:
+       gen_pool_destroy(pool);
+fail:
+       pr_err("Failed to create SRAM pool\n");
+       return -ENOMEM;
 }
+core_initcall(sram_init);
index 097cf4e8405260e738ee02dcec3dd29b7c5dbd33..994c4545e2b7ecac3bc50b95db9e871aebf7d8e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Atmel Corporation
+ * Copyright (C) 2006, 2008 Atmel 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
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/sysdev.h>
 
 #include <asm/io.h>
 
 #include "intc.h"
 
 struct intc {
-       void __iomem    *regs;
-       struct irq_chip chip;
+       void __iomem            *regs;
+       struct irq_chip         chip;
+       struct sys_device       sysdev;
+#ifdef CONFIG_PM
+       unsigned long           suspend_ipr;
+       unsigned long           saved_ipr[64];
+#endif
 };
 
 extern struct platform_device at32_intc0_device;
@@ -136,6 +142,74 @@ fail:
        panic("Interrupt controller initialization failed!\n");
 }
 
+#ifdef CONFIG_PM
+void intc_set_suspend_handler(unsigned long offset)
+{
+       intc0.suspend_ipr = offset;
+}
+
+static int intc_suspend(struct sys_device *sdev, pm_message_t state)
+{
+       struct intc *intc = container_of(sdev, struct intc, sysdev);
+       int i;
+
+       if (unlikely(!irqs_disabled())) {
+               pr_err("intc_suspend: called with interrupts enabled\n");
+               return -EINVAL;
+       }
+
+       if (unlikely(!intc->suspend_ipr)) {
+               pr_err("intc_suspend: suspend_ipr not initialized\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 64; i++) {
+               intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
+               intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
+       }
+
+       return 0;
+}
+
+static int intc_resume(struct sys_device *sdev)
+{
+       struct intc *intc = container_of(sdev, struct intc, sysdev);
+       int i;
+
+       WARN_ON(!irqs_disabled());
+
+       for (i = 0; i < 64; i++)
+               intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
+
+       return 0;
+}
+#else
+#define intc_suspend   NULL
+#define intc_resume    NULL
+#endif
+
+static struct sysdev_class intc_class = {
+       .name           = "intc",
+       .suspend        = intc_suspend,
+       .resume         = intc_resume,
+};
+
+static int __init intc_init_sysdev(void)
+{
+       int ret;
+
+       ret = sysdev_class_register(&intc_class);
+       if (ret)
+               return ret;
+
+       intc0.sysdev.id = 0;
+       intc0.sysdev.cls = &intc_class;
+       ret = sysdev_register(&intc0.sysdev);
+
+       return ret;
+}
+device_initcall(intc_init_sysdev);
+
 unsigned long intc_get_pending(unsigned int group)
 {
        return intc_readl(&intc0, INTREQ0 + 4 * group);
similarity index 90%
rename from arch/avr32/mach-at32ap/at32ap.c
rename to arch/avr32/mach-at32ap/pdc.c
index 7c4987f3287a7ca52d944ee30bc435225bdaac56..1040bda4fda7c843ea0d4955129f17cc94ab79bd 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/arch/init.h>
-
-void __init setup_platform(void)
-{
-       at32_clock_init();
-       at32_portmux_init();
-}
-
 static int __init pdc_probe(struct platform_device *pdev)
 {
        struct clk *pclk, *hclk;
index 38a8fa31c0b5c8de591ae8f39a08c2e90d2a862b..60da03ba7117e0c9a62ad4756ac5fa0aecf7d756 100644 (file)
@@ -318,6 +318,8 @@ static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
                const char *label;
 
                label = gpiochip_is_requested(chip, i);
+               if (!label && (imr & mask))
+                       label = "[irq]";
                if (!label)
                        continue;
 
index 7795116a483af37707a66ae57c1f1da49e59a41a..9484dfcc08f224e925a8408c1b5d9edd30ccb6f6 100644 (file)
@@ -57,7 +57,7 @@
 
 /* Bitfields in IFDR */
 
-/* Bitfields in ISFR */
+/* Bitfields in IFSR */
 
 /* Bitfields in SODR */
 
index 949e2485e2788bc440f2b4242a66e763be33eb2f..0a53ad314ff429a54bfcc16e48898cd523a82b38 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/arch/pm.h>
 
+#include "pm.h"
+#include "sdramc.h"
+
+/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
+#define PM_BASE        -0x100000
+
        .section .bss, "wa", @nobits
        .global disable_idle_sleep
        .type   disable_idle_sleep, @object
@@ -64,3 +70,105 @@ cpu_idle_skip_sleep:
        unmask_interrupts
        retal   r12
        .size   cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
+
+#ifdef CONFIG_PM
+       .section .init.text, "ax", @progbits
+
+       .global pm_exception
+       .type   pm_exception, @function
+pm_exception:
+       /*
+        * Exceptions are masked when we switch to this handler, so
+        * we'll only get "unrecoverable" exceptions (offset 0.)
+        */
+       sub     r12, pc, . - .Lpanic_msg
+       lddpc   pc, .Lpanic_addr
+
+       .align  2
+.Lpanic_addr:
+       .long   panic
+.Lpanic_msg:
+       .asciz  "Unrecoverable exception during suspend\n"
+       .size   pm_exception, . - pm_exception
+
+       .global pm_irq0
+       .type   pm_irq0, @function
+pm_irq0:
+       /* Disable interrupts and return after the sleep instruction */
+       mfsr    r9, SYSREG_RSR_INT0
+       mtsr    SYSREG_RAR_INT0, r8
+       sbr     r9, SYSREG_GM_OFFSET
+       mtsr    SYSREG_RSR_INT0, r9
+       rete
+
+       /*
+        * void cpu_enter_standby(unsigned long sdramc_base)
+        *
+        * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers
+        * are suspended and interrupts are disabled. Interrupts
+        * marked as 'wakeup' event sources may still come along and
+        * get us out of here.
+        *
+        * The SDRAM will be put into self-refresh mode (which does
+        * not require a clock from the CPU), and the CPU will be put
+        * into "frozen" mode (HSB bus stopped). The SDRAM controller
+        * will automatically bring the SDRAM into normal mode on the
+        * first access, and the power manager will automatically
+        * start the HSB and CPU clocks upon a wakeup event.
+        *
+        * This code uses the same "skip sleep" technique as above.
+        * It is very important that we jump directly to
+        * cpu_after_sleep after the sleep instruction since that's
+        * where we'll end up if the interrupt handler decides that we
+        * need to skip the sleep instruction.
+        */
+       .global pm_standby
+       .type   pm_standby, @function
+pm_standby:
+       /*
+        * interrupts are already masked at this point, and EVBA
+        * points to pm_exception above.
+        */
+       ld.w    r10, r12[SDRAMC_LPR]
+       sub     r8, pc, . - 1f          /* return address for irq handler */
+       mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
+       bfins   r10, r11, 0, 2          /* LPCB <- self Refresh */
+       sync    0                       /* flush write buffer */
+       st.w    r12[SDRAMC_LPR], r11    /* put SDRAM in self-refresh mode */
+       ld.w    r11, r12[SDRAMC_LPR]
+       unmask_interrupts
+       sleep   CPU_SLEEP_FROZEN
+1:     mask_interrupts
+       retal   r12
+       .size   pm_standby, . - pm_standby
+
+       .global pm_suspend_to_ram
+       .type   pm_suspend_to_ram, @function
+pm_suspend_to_ram:
+       /*
+        * interrupts are already masked at this point, and EVBA
+        * points to pm_exception above.
+        */
+       mov     r11, 0
+       cache   r11[2], 8               /* clean all dcache lines */
+       sync    0                       /* flush write buffer */
+       ld.w    r10, r12[SDRAMC_LPR]
+       sub     r8, pc, . - 1f          /* return address for irq handler */
+       mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
+       bfins   r10, r11, 0, 2          /* LPCB <- self refresh */
+       st.w    r12[SDRAMC_LPR], r10    /* put SDRAM in self-refresh mode */
+       ld.w    r11, r12[SDRAMC_LPR]
+
+       unmask_interrupts
+       sleep   CPU_SLEEP_STOP
+1:     mask_interrupts
+
+       retal   r12
+       .size   pm_suspend_to_ram, . - pm_suspend_to_ram
+
+       .global pm_sram_end
+       .type   pm_sram_end, @function
+pm_sram_end:
+       .size   pm_sram_end, 0
+
+#endif /* CONFIG_PM */
diff --git a/arch/avr32/mach-at32ap/pm.c b/arch/avr32/mach-at32ap/pm.c
new file mode 100644 (file)
index 0000000..0b76432
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * AVR32 AP Power Management
+ *
+ * Copyright (C) 2008 Atmel 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.
+ */
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <linux/vmalloc.h>
+
+#include <asm/cacheflush.h>
+#include <asm/sysreg.h>
+
+#include <asm/arch/pm.h>
+#include <asm/arch/sram.h>
+
+/* FIXME: This is only valid for AP7000 */
+#define SDRAMC_BASE    0xfff03800
+
+#include "sdramc.h"
+
+#define SRAM_PAGE_FLAGS        (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1)        \
+                               | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
+
+
+static unsigned long   pm_sram_start;
+static size_t          pm_sram_size;
+static struct vm_struct        *pm_sram_area;
+
+static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
+static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
+
+/*
+ * Must be called with interrupts disabled. Exceptions will be masked
+ * on return (i.e. all exceptions will be "unrecoverable".)
+ */
+static void *avr32_pm_map_sram(void)
+{
+       unsigned long   vaddr;
+       unsigned long   page_addr;
+       u32             tlbehi;
+       u32             mmucr;
+
+       vaddr = (unsigned long)pm_sram_area->addr;
+       page_addr = pm_sram_start & PAGE_MASK;
+
+       /*
+        * Mask exceptions and grab the first TLB entry. We won't be
+        * needing it while sleeping.
+        */
+       asm volatile("ssrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
+
+       mmucr = sysreg_read(MMUCR);
+       tlbehi = sysreg_read(TLBEHI);
+       sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
+
+       tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+       tlbehi |= vaddr & PAGE_MASK;
+       tlbehi |= SYSREG_BIT(TLBEHI_V);
+
+       sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
+       sysreg_write(TLBEHI, tlbehi);
+       __builtin_tlbw();
+
+       return (void *)(vaddr + pm_sram_start - page_addr);
+}
+
+/*
+ * Must be called with interrupts disabled. Exceptions will be
+ * unmasked on return.
+ */
+static void avr32_pm_unmap_sram(void)
+{
+       u32     mmucr;
+       u32     tlbehi;
+       u32     tlbarlo;
+
+       /* Going to update TLB entry at index 0 */
+       mmucr = sysreg_read(MMUCR);
+       tlbehi = sysreg_read(TLBEHI);
+       sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
+
+       /* Clear the "valid" bit */
+       tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+       sysreg_write(TLBEHI, tlbehi);
+
+       /* Mark it as "not accessed" */
+       tlbarlo = sysreg_read(TLBARLO);
+       sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
+
+       /* Update the TLB */
+       __builtin_tlbw();
+
+       /* Unmask exceptions */
+       asm volatile("csrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
+}
+
+static int avr32_pm_valid_state(suspend_state_t state)
+{
+       switch (state) {
+       case PM_SUSPEND_ON:
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+static int avr32_pm_enter(suspend_state_t state)
+{
+       u32             lpr_saved;
+       u32             evba_saved;
+       void            *sram;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+               sram = avr32_pm_map_sram();
+
+               /* Switch to in-sram exception handlers */
+               evba_saved = sysreg_read(EVBA);
+               sysreg_write(EVBA, (unsigned long)sram);
+
+               /*
+                * Save the LPR register so that we can re-enable
+                * SDRAM Low Power mode on resume.
+                */
+               lpr_saved = sdramc_readl(LPR);
+               pr_debug("%s: Entering standby...\n", __func__);
+               avr32_pm_enter_standby(SDRAMC_BASE);
+               sdramc_writel(LPR, lpr_saved);
+
+               /* Switch back to regular exception handlers */
+               sysreg_write(EVBA, evba_saved);
+
+               avr32_pm_unmap_sram();
+               break;
+
+       case PM_SUSPEND_MEM:
+               sram = avr32_pm_map_sram();
+
+               /* Switch to in-sram exception handlers */
+               evba_saved = sysreg_read(EVBA);
+               sysreg_write(EVBA, (unsigned long)sram);
+
+               /*
+                * Save the LPR register so that we can re-enable
+                * SDRAM Low Power mode on resume.
+                */
+               lpr_saved = sdramc_readl(LPR);
+               pr_debug("%s: Entering suspend-to-ram...\n", __func__);
+               avr32_pm_enter_str(SDRAMC_BASE);
+               sdramc_writel(LPR, lpr_saved);
+
+               /* Switch back to regular exception handlers */
+               sysreg_write(EVBA, evba_saved);
+
+               avr32_pm_unmap_sram();
+               break;
+
+       case PM_SUSPEND_ON:
+               pr_debug("%s: Entering idle...\n", __func__);
+               cpu_enter_idle();
+               break;
+
+       default:
+               pr_debug("%s: Invalid suspend state %d\n", __func__, state);
+               goto out;
+       }
+
+       pr_debug("%s: wakeup\n", __func__);
+
+out:
+       return 0;
+}
+
+static struct platform_suspend_ops avr32_pm_ops = {
+       .valid  = avr32_pm_valid_state,
+       .enter  = avr32_pm_enter,
+};
+
+static unsigned long avr32_pm_offset(void *symbol)
+{
+       extern u8 pm_exception[];
+
+       return (unsigned long)symbol - (unsigned long)pm_exception;
+}
+
+static int __init avr32_pm_init(void)
+{
+       extern u8 pm_exception[];
+       extern u8 pm_irq0[];
+       extern u8 pm_standby[];
+       extern u8 pm_suspend_to_ram[];
+       extern u8 pm_sram_end[];
+       void *dst;
+
+       /*
+        * To keep things simple, we depend on not needing more than a
+        * single page.
+        */
+       pm_sram_size = avr32_pm_offset(pm_sram_end);
+       if (pm_sram_size > PAGE_SIZE)
+               goto err;
+
+       pm_sram_start = sram_alloc(pm_sram_size);
+       if (!pm_sram_start)
+               goto err_alloc_sram;
+
+       /* Grab a virtual area we can use later on. */
+       pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
+       if (!pm_sram_area)
+               goto err_vm_area;
+       pm_sram_area->phys_addr = pm_sram_start;
+
+       local_irq_disable();
+       dst = avr32_pm_map_sram();
+       memcpy(dst, pm_exception, pm_sram_size);
+       flush_dcache_region(dst, pm_sram_size);
+       invalidate_icache_region(dst, pm_sram_size);
+       avr32_pm_unmap_sram();
+       local_irq_enable();
+
+       avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
+       avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
+       intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
+
+       suspend_set_ops(&avr32_pm_ops);
+
+       printk("AVR32 AP Power Management enabled\n");
+
+       return 0;
+
+err_vm_area:
+       sram_free(pm_sram_start, pm_sram_size);
+err_alloc_sram:
+err:
+       pr_err("AVR32 Power Management initialization failed\n");
+       return -ENOMEM;
+}
+arch_initcall(avr32_pm_init);
diff --git a/arch/avr32/mach-at32ap/sdramc.h b/arch/avr32/mach-at32ap/sdramc.h
new file mode 100644 (file)
index 0000000..66eeaed
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Register definitions for the AT32AP SDRAM Controller
+ *
+ * Copyright (C) 2008 Atmel 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.
+ */
+
+/* Register offsets */
+#define SDRAMC_MR                      0x0000
+#define SDRAMC_TR                      0x0004
+#define SDRAMC_CR                      0x0008
+#define SDRAMC_HSR                     0x000c
+#define SDRAMC_LPR                     0x0010
+#define SDRAMC_IER                     0x0014
+#define SDRAMC_IDR                     0x0018
+#define SDRAMC_IMR                     0x001c
+#define SDRAMC_ISR                     0x0020
+#define SDRAMC_MDR                     0x0024
+
+/* MR - Mode Register */
+#define SDRAMC_MR_MODE_NORMAL          (  0 <<  0)
+#define SDRAMC_MR_MODE_NOP             (  1 <<  0)
+#define SDRAMC_MR_MODE_BANKS_PRECHARGE (  2 <<  0)
+#define SDRAMC_MR_MODE_LOAD_MODE       (  3 <<  0)
+#define SDRAMC_MR_MODE_AUTO_REFRESH    (  4 <<  0)
+#define SDRAMC_MR_MODE_EXT_LOAD_MODE   (  5 <<  0)
+#define SDRAMC_MR_MODE_POWER_DOWN      (  6 <<  0)
+
+/* CR - Configuration Register */
+#define SDRAMC_CR_NC_8_BITS            (  0 <<  0)
+#define SDRAMC_CR_NC_9_BITS            (  1 <<  0)
+#define SDRAMC_CR_NC_10_BITS           (  2 <<  0)
+#define SDRAMC_CR_NC_11_BITS           (  3 <<  0)
+#define SDRAMC_CR_NR_11_BITS           (  0 <<  2)
+#define SDRAMC_CR_NR_12_BITS           (  1 <<  2)
+#define SDRAMC_CR_NR_13_BITS           (  2 <<  2)
+#define SDRAMC_CR_NB_2_BANKS           (  0 <<  4)
+#define SDRAMC_CR_NB_4_BANKS           (  1 <<  4)
+#define SDRAMC_CR_CAS(x)               ((x) <<  5)
+#define SDRAMC_CR_DBW_32_BITS          (  0 <<  7)
+#define SDRAMC_CR_DBW_16_BITS          (  1 <<  7)
+#define SDRAMC_CR_TWR(x)               ((x) <<  8)
+#define SDRAMC_CR_TRC(x)               ((x) << 12)
+#define SDRAMC_CR_TRP(x)               ((x) << 16)
+#define SDRAMC_CR_TRCD(x)              ((x) << 20)
+#define SDRAMC_CR_TRAS(x)              ((x) << 24)
+#define SDRAMC_CR_TXSR(x)              ((x) << 28)
+
+/* HSR - High Speed Register */
+#define SDRAMC_HSR_DA                  (  1 <<  0)
+
+/* LPR - Low Power Register */
+#define SDRAMC_LPR_LPCB_INHIBIT                (  0 <<  0)
+#define SDRAMC_LPR_LPCB_SELF_RFR       (  1 <<  0)
+#define SDRAMC_LPR_LPCB_PDOWN          (  2 <<  0)
+#define SDRAMC_LPR_LPCB_DEEP_PDOWN     (  3 <<  0)
+#define SDRAMC_LPR_PASR(x)             ((x) <<  4)
+#define SDRAMC_LPR_TCSR(x)             ((x) <<  8)
+#define SDRAMC_LPR_DS(x)               ((x) << 10)
+#define SDRAMC_LPR_TIMEOUT(x)          ((x) << 12)
+
+/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */
+#define SDRAMC_ISR_RES                 (  1 <<  0)
+
+/* MDR - Memory Device Register */
+#define SDRAMC_MDR_MD_SDRAM            (  0 <<  0)
+#define SDRAMC_MDR_MD_LOW_PWR_SDRAM    (  1 <<  0)
+
+/* Register access macros */
+#define sdramc_readl(reg) \
+       __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
+#define sdramc_writel(reg, value) \
+       __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
index 0e64ddc45e3750f17e33b5be98789c9bed6176cc..3f90a87527bb27fe6ce997c0881a1ecfcbbdcc87 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/swap.h>
 #include <linux/init.h>
 #include <linux/mmzone.h>
+#include <linux/module.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
 #include <linux/nodemask.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
 
+#define __page_aligned __attribute__((section(".data.page_aligned")))
+
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-pgd_t swapper_pg_dir[PTRS_PER_PGD];
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned;
 
 struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
 
 /*
  * Cache of MMU context last used.
@@ -106,19 +110,9 @@ void __init paging_init(void)
        zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0),
                                                 PAGE_SIZE);
 
-       {
-               pgd_t *pg_dir;
-               int i;
-
-               pg_dir = swapper_pg_dir;
-               sysreg_write(PTBR, (unsigned long)pg_dir);
-
-               for (i = 0; i < PTRS_PER_PGD; i++)
-                       pgd_val(pg_dir[i]) = 0;
-
-               enable_mmu();
-               printk ("CPU: Paging enabled\n");
-       }
+       sysreg_write(PTBR, (unsigned long)swapper_pg_dir);
+       enable_mmu();
+       printk ("CPU: Paging enabled\n");
 
        for_each_online_node(nid) {
                pg_data_t *pgdat = NODE_DATA(nid);
index cd12edbea9f26c403bdc5a3c85f034e76766fc9a..06677be98ffba5fcb0143dac626bf96235fd1e16 100644 (file)
 
 #include <asm/mmu_context.h>
 
-#define _TLBEHI_I      0x100
+/* TODO: Get the correct number from the CONFIG1 system register */
+#define NR_TLB_ENTRIES 32
 
-void show_dtlb_entry(unsigned int index)
+static void show_dtlb_entry(unsigned int index)
 {
-       unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
+       u32 tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
        unsigned long flags;
 
        local_irq_save(flags);
        mmucr_save = sysreg_read(MMUCR);
        tlbehi_save = sysreg_read(TLBEHI);
-       mmucr = mmucr_save & 0x13;
-       mmucr |= index << 14;
+       mmucr = SYSREG_BFINS(DRP, index, mmucr_save);
        sysreg_write(MMUCR, mmucr);
 
-       asm volatile("tlbr" : : : "memory");
+       __builtin_tlbr();
        cpu_sync_pipeline();
 
        tlbehi = sysreg_read(TLBEHI);
@@ -33,15 +33,17 @@ void show_dtlb_entry(unsigned int index)
 
        printk("%2u: %c %c %02x   %05x %05x %o  %o  %c %c %c %c\n",
               index,
-              (tlbehi & 0x200)?'1':'0',
-              (tlbelo & 0x100)?'1':'0',
-              (tlbehi & 0xff),
-              (tlbehi >> 12), (tlbelo >> 12),
-              (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
-              (tlbelo & 0x200)?'1':'0',
-              (tlbelo & 0x080)?'1':'0',
-              (tlbelo & 0x001)?'1':'0',
-              (tlbelo & 0x002)?'1':'0');
+              SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
+              SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
+              SYSREG_BFEXT(ASID, tlbehi),
+              SYSREG_BFEXT(VPN, tlbehi) >> 2,
+              SYSREG_BFEXT(PFN, tlbelo) >> 2,
+              SYSREG_BFEXT(AP, tlbelo),
+              SYSREG_BFEXT(SZ, tlbelo),
+              SYSREG_BFEXT(TLBELO_C, tlbelo) ? 'C' : ' ',
+              SYSREG_BFEXT(B, tlbelo) ? 'B' : ' ',
+              SYSREG_BFEXT(W, tlbelo) ? 'W' : ' ',
+              SYSREG_BFEXT(TLBELO_D, tlbelo) ? 'D' : ' ');
 
        sysreg_write(MMUCR, mmucr_save);
        sysreg_write(TLBEHI, tlbehi_save);
@@ -54,29 +56,33 @@ void dump_dtlb(void)
        unsigned int i;
 
        printk("ID  V G ASID VPN   PFN   AP SZ C B W D\n");
-       for (i = 0; i < 32; i++)
+       for (i = 0; i < NR_TLB_ENTRIES; i++)
                show_dtlb_entry(i);
 }
 
-static unsigned long last_mmucr;
-
-static inline void set_replacement_pointer(unsigned shift)
+static void update_dtlb(unsigned long address, pte_t pte)
 {
-       unsigned long mmucr, mmucr_save;
+       u32 tlbehi;
+       u32 mmucr;
 
-       mmucr = mmucr_save = sysreg_read(MMUCR);
+       /*
+        * We're not changing the ASID here, so no need to flush the
+        * pipeline.
+        */
+       tlbehi = sysreg_read(TLBEHI);
+       tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+       tlbehi |= address & MMU_VPN_MASK;
+       tlbehi |= SYSREG_BIT(TLBEHI_V);
+       sysreg_write(TLBEHI, tlbehi);
 
        /* Does this mapping already exist? */
-       __asm__ __volatile__(
-               "       tlbs\n"
-               "       mfsr %0, %1"
-               : "=r"(mmucr)
-               : "i"(SYSREG_MMUCR));
+       __builtin_tlbs();
+       mmucr = sysreg_read(MMUCR);
 
        if (mmucr & SYSREG_BIT(MMUCR_N)) {
                /* Not found -- pick a not-recently-accessed entry */
-               unsigned long rp;
-               unsigned long tlbar = sysreg_read(TLBARLO);
+               unsigned int rp;
+               u32 tlbar = sysreg_read(TLBARLO);
 
                rp = 32 - fls(tlbar);
                if (rp == 32) {
@@ -84,30 +90,14 @@ static inline void set_replacement_pointer(unsigned shift)
                        sysreg_write(TLBARLO, -1L);
                }
 
-               mmucr &= 0x13;
-               mmucr |= (rp << shift);
-
+               mmucr = SYSREG_BFINS(DRP, rp, mmucr);
                sysreg_write(MMUCR, mmucr);
        }
 
-       last_mmucr = mmucr;
-}
-
-static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid)
-{
-       unsigned long vpn;
-
-       vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid;
-       sysreg_write(TLBEHI, vpn);
-       cpu_sync_pipeline();
-
-       set_replacement_pointer(14);
-
        sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK);
 
        /* Let's go */
-       asm volatile("nop\n\ttlbw" : : : "memory");
-       cpu_sync_pipeline();
+       __builtin_tlbw();
 }
 
 void update_mmu_cache(struct vm_area_struct *vma,
@@ -120,39 +110,40 @@ void update_mmu_cache(struct vm_area_struct *vma,
                return;
 
        local_irq_save(flags);
-       update_dtlb(address, pte, get_asid());
+       update_dtlb(address, pte);
        local_irq_restore(flags);
 }
 
-void __flush_tlb_page(unsigned long asid, unsigned long page)
+static void __flush_tlb_page(unsigned long asid, unsigned long page)
 {
-       unsigned long mmucr, tlbehi;
+       u32 mmucr, tlbehi;
 
-       page |= asid;
-       sysreg_write(TLBEHI, page);
-       cpu_sync_pipeline();
-       asm volatile("tlbs");
+       /*
+        * Caller is responsible for masking out non-PFN bits in page
+        * and changing the current ASID if necessary. This means that
+        * we don't need to flush the pipeline after writing TLBEHI.
+        */
+       tlbehi = page | asid;
+       sysreg_write(TLBEHI, tlbehi);
+
+       __builtin_tlbs();
        mmucr = sysreg_read(MMUCR);
 
        if (!(mmucr & SYSREG_BIT(MMUCR_N))) {
-               unsigned long tlbarlo;
-               unsigned long entry;
+               unsigned int entry;
+               u32 tlbarlo;
 
                /* Clear the "valid" bit */
-               tlbehi = sysreg_read(TLBEHI);
-               tlbehi &= ~_TLBEHI_VALID;
                sysreg_write(TLBEHI, tlbehi);
-               cpu_sync_pipeline();
 
                /* mark the entry as "not accessed" */
-               entry = (mmucr >> 14) & 0x3f;
+               entry = SYSREG_BFEXT(DRP, mmucr);
                tlbarlo = sysreg_read(TLBARLO);
-               tlbarlo |= (0x80000000 >> entry);
+               tlbarlo |= (0x80000000UL >> entry);
                sysreg_write(TLBARLO, tlbarlo);
 
                /* update the entry with valid bit clear */
-               asm volatile("tlbw");
-               cpu_sync_pipeline();
+               __builtin_tlbw();
        }
 }
 
@@ -190,17 +181,22 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 
                local_irq_save(flags);
                size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
                if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
                        mm->context = NO_CONTEXT;
                        if (mm == current->mm)
                                activate_context(mm);
                } else {
-                       unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK;
-                       unsigned long saved_asid = MMU_NO_ASID;
+                       unsigned long asid;
+                       unsigned long saved_asid;
+
+                       asid = mm->context & MMU_CONTEXT_ASID_MASK;
+                       saved_asid = MMU_NO_ASID;
 
                        start &= PAGE_MASK;
                        end += (PAGE_SIZE - 1);
                        end &= PAGE_MASK;
+
                        if (mm != current->mm) {
                                saved_asid = get_asid();
                                set_asid(asid);
@@ -218,33 +214,34 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 }
 
 /*
- * TODO: If this is only called for addresses > TASK_SIZE, we can probably
- * skip the ASID stuff and just use the Global bit...
+ * This function depends on the pages to be flushed having the G
+ * (global) bit set in their pte. This is true for all
+ * PAGE_KERNEL(_RO) pages.
  */
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
        unsigned long flags;
        int size;
 
-       local_irq_save(flags);
        size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
        if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
                flush_tlb_all();
        } else {
-               unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK;
-               unsigned long saved_asid = get_asid();
+               unsigned long asid;
+
+               local_irq_save(flags);
+               asid = get_asid();
 
                start &= PAGE_MASK;
                end += (PAGE_SIZE - 1);
                end &= PAGE_MASK;
-               set_asid(asid);
+
                while (start < end) {
                        __flush_tlb_page(asid, start);
                        start += PAGE_SIZE;
                }
-               set_asid(saved_asid);
+               local_irq_restore(flags);
        }
-       local_irq_restore(flags);
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
@@ -280,7 +277,7 @@ static void *tlb_start(struct seq_file *tlb, loff_t *pos)
 {
        static unsigned long tlb_index;
 
-       if (*pos >= 32)
+       if (*pos >= NR_TLB_ENTRIES)
                return NULL;
 
        tlb_index = 0;
@@ -291,7 +288,7 @@ static void *tlb_next(struct seq_file *tlb, void *v, loff_t *pos)
 {
        unsigned long *index = v;
 
-       if (*index >= 31)
+       if (*index >= NR_TLB_ENTRIES - 1)
                return NULL;
 
        ++*pos;
@@ -313,16 +310,16 @@ static int tlb_show(struct seq_file *tlb, void *v)
        if (*index == 0)
                seq_puts(tlb, "ID  V G ASID VPN   PFN   AP SZ C B W D\n");
 
-       BUG_ON(*index >= 32);
+       BUG_ON(*index >= NR_TLB_ENTRIES);
 
        local_irq_save(flags);
        mmucr_save = sysreg_read(MMUCR);
        tlbehi_save = sysreg_read(TLBEHI);
-       mmucr = mmucr_save & 0x13;
-       mmucr |= *index << 14;
+       mmucr = SYSREG_BFINS(DRP, *index, mmucr_save);
        sysreg_write(MMUCR, mmucr);
 
-       asm volatile("tlbr" : : : "memory");
+       /* TLBR might change the ASID */
+       __builtin_tlbr();
        cpu_sync_pipeline();
 
        tlbehi = sysreg_read(TLBEHI);
@@ -334,16 +331,18 @@ static int tlb_show(struct seq_file *tlb, void *v)
        local_irq_restore(flags);
 
        seq_printf(tlb, "%2lu: %c %c %02x   %05x %05x %o  %o  %c %c %c %c\n",
-              *index,
-              (tlbehi & 0x200)?'1':'0',
-              (tlbelo & 0x100)?'1':'0',
-              (tlbehi & 0xff),
-              (tlbehi >> 12), (tlbelo >> 12),
-              (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
-              (tlbelo & 0x200)?'1':'0',
-              (tlbelo & 0x080)?'1':'0',
-              (tlbelo & 0x001)?'1':'0',
-              (tlbelo & 0x002)?'1':'0');
+                  *index,
+                  SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
+                  SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(ASID, tlbehi),
+                  SYSREG_BFEXT(VPN, tlbehi) >> 2,
+                  SYSREG_BFEXT(PFN, tlbelo) >> 2,
+                  SYSREG_BFEXT(AP, tlbelo),
+                  SYSREG_BFEXT(SZ, tlbelo),
+                  SYSREG_BFEXT(TLBELO_C, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(B, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(W, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(TLBELO_D, tlbelo) ? '1' : '0');
 
        return 0;
 }
index 107e492cb47efa8fab159a8714d89cdcac29d5ae..5dc8f8028d520b6c0a09dd4e0a6ffb70d4891d84 100644 (file)
@@ -146,6 +146,7 @@ config MATHEMU
 config COMPAT
        bool "Kernel support for 31 bit emulation"
        depends on 64BIT
+       select COMPAT_BINFMT_ELF
        help
          Select this option if you want to enable your system kernel to
          handle system-calls from ELF binaries for 31 bit ESA.  This option
@@ -312,6 +313,10 @@ config ARCH_SPARSEMEM_DEFAULT
 config ARCH_SELECT_MEMORY_MODEL
        def_bool y
 
+config ARCH_ENABLE_MEMORY_HOTPLUG
+       def_bool y
+       depends on SPARSEMEM
+
 source "mm/Kconfig"
 
 comment "I/O subsystem configuration"
@@ -344,6 +349,22 @@ config QDIO_DEBUG
 
          If unsure, say N.
 
+config CHSC_SCH
+       tristate "Support for CHSC subchannels"
+       help
+         This driver allows usage of CHSC subchannels. A CHSC subchannel
+         is usually present on LPAR only.
+         The driver creates a device /dev/chsc, which may be used to
+         obtain I/O configuration information about the machine and
+         to issue asynchronous chsc commands (DANGEROUS).
+         You will usually only want to use this interface on a special
+         LPAR designated for system management.
+
+         To compile this driver as a module, choose M here: the
+         module will be called chsc_sch.
+
+         If unsure, say N.
+
 comment "Misc"
 
 config IPL
index db3ae8505103812a49b0d7e5a675251ec005f928..17a2636fec0a4a2395b5ba67496c504d3c50b550 100644 (file)
@@ -3,13 +3,11 @@
  *
  * Definitions and interface for Linux - z/VM Monitor Stream.
  *
- * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright IBM Corp. 2003, 2008
  *
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
-//#define APPLDATA_DEBUG                       /* Debug messages on/off */
-
 #define APPLDATA_MAX_REC_SIZE    4024  /* Maximum size of the */
                                        /* data buffer */
 #define APPLDATA_MAX_PROCS 100
 #define P_ERROR(x...)  printk(KERN_ERR MY_PRINT_NAME " error: " x)
 #define P_WARNING(x...)        printk(KERN_WARNING MY_PRINT_NAME " status: " x)
 
-#ifdef APPLDATA_DEBUG
-#define P_DEBUG(x...)   printk(KERN_DEBUG MY_PRINT_NAME " debug: " x)
-#else
-#define P_DEBUG(x...)   do {} while (0)
-#endif
-
 struct appldata_ops {
        struct list_head list;
        struct ctl_table_header *sysctl_header;
index ad40729bec3d9a062925b2b2db3bf7d990d0ea3e..9cb3d92447a35651c5c67d5f495a5d1fa5981b2f 100644 (file)
@@ -5,7 +5,7 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright IBM Corp. 2003, 2008
  *
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
@@ -108,9 +108,6 @@ static LIST_HEAD(appldata_ops_list);
  */
 static void appldata_timer_function(unsigned long data)
 {
-       P_DEBUG("   -= Timer =-\n");
-       P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
-               atomic_read(&appldata_expire_count));
        if (atomic_dec_and_test(&appldata_expire_count)) {
                atomic_set(&appldata_expire_count, num_online_cpus());
                queue_work(appldata_wq, (struct work_struct *) data);
@@ -128,14 +125,11 @@ static void appldata_work_fn(struct work_struct *work)
        struct appldata_ops *ops;
        int i;
 
-       P_DEBUG("  -= Work Queue =-\n");
        i = 0;
        get_online_cpus();
        spin_lock(&appldata_ops_lock);
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
-               P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n",
-                       ++i, ops->active, ops->name);
                if (ops->active == 1) {
                        ops->callback(ops->data);
                }
@@ -212,7 +206,6 @@ __appldata_vtimer_setup(int cmd)
                                                 0, 1);
                }
                appldata_timer_active = 1;
-               P_INFO("Monitoring timer started.\n");
                break;
        case APPLDATA_DEL_TIMER:
                for_each_online_cpu(i)
@@ -221,7 +214,6 @@ __appldata_vtimer_setup(int cmd)
                        break;
                appldata_timer_active = 0;
                atomic_set(&appldata_expire_count, num_online_cpus());
-               P_INFO("Monitoring timer stopped.\n");
                break;
        case APPLDATA_MOD_TIMER:
                per_cpu_interval = (u64) (appldata_interval*1000 /
@@ -313,10 +305,8 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
        }
        interval = 0;
        sscanf(buf, "%i", &interval);
-       if (interval <= 0) {
-               P_ERROR("Timer CPU interval has to be > 0!\n");
+       if (interval <= 0)
                return -EINVAL;
-       }
 
        get_online_cpus();
        spin_lock(&appldata_timer_lock);
@@ -324,9 +314,6 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
        spin_unlock(&appldata_timer_lock);
        put_online_cpus();
-
-       P_INFO("Monitoring CPU interval set to %u milliseconds.\n",
-                interval);
 out:
        *lenp = len;
        *ppos += len;
@@ -406,23 +393,16 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                        P_ERROR("START DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
                        module_put(ops->owner);
-               } else {
-                       P_INFO("Monitoring %s data enabled, "
-                               "DIAG 0xDC started.\n", ops->name);
+               } else
                        ops->active = 1;
-               }
        } else if ((buf[0] == '0') && (ops->active == 1)) {
                ops->active = 0;
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
                                (unsigned long) ops->data, ops->size,
                                ops->mod_lvl);
-               if (rc != 0) {
+               if (rc != 0)
                        P_ERROR("STOP DIAG 0xDC for %s failed, "
                                "return code: %d\n", ops->name, rc);
-               } else {
-                       P_INFO("Monitoring %s data disabled, "
-                               "DIAG 0xDC stopped.\n", ops->name);
-               }
                module_put(ops->owner);
        }
        spin_unlock(&appldata_ops_lock);
@@ -468,7 +448,6 @@ int appldata_register_ops(struct appldata_ops *ops)
        ops->sysctl_header = register_sysctl_table(ops->ctl_table);
        if (!ops->sysctl_header)
                goto out;
-       P_INFO("%s-ops registered!\n", ops->name);
        return 0;
 out:
        spin_lock(&appldata_ops_lock);
@@ -490,7 +469,6 @@ void appldata_unregister_ops(struct appldata_ops *ops)
        spin_unlock(&appldata_ops_lock);
        unregister_sysctl_table(ops->sysctl_header);
        kfree(ops->ctl_table);
-       P_INFO("%s-ops unregistered!\n", ops->name);
 }
 /********************** module-ops management <END> **************************/
 
@@ -553,14 +531,9 @@ static int __init appldata_init(void)
 {
        int i;
 
-       P_DEBUG("sizeof(parameter_list) = %lu\n",
-               sizeof(struct appldata_parameter_list));
-
        appldata_wq = create_singlethread_workqueue("appldata");
-       if (!appldata_wq) {
-               P_ERROR("Could not create work queue\n");
+       if (!appldata_wq)
                return -ENOMEM;
-       }
 
        get_online_cpus();
        for_each_online_cpu(i)
@@ -571,8 +544,6 @@ static int __init appldata_init(void)
        register_hotcpu_notifier(&appldata_nb);
 
        appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
-
-       P_DEBUG("Base interface initialized.\n");
        return 0;
 }
 
@@ -584,7 +555,9 @@ EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
 EXPORT_SYMBOL_GPL(appldata_diag);
 
+#ifdef CONFIG_SWAP
 EXPORT_SYMBOL_GPL(si_swapinfo);
+#endif
 EXPORT_SYMBOL_GPL(nr_threads);
 EXPORT_SYMBOL_GPL(nr_running);
 EXPORT_SYMBOL_GPL(nr_iowait);
index 51181ccdb87b255699a3857f24d0ddac80e45699..3ed56b7d1b2f3d1cf8b68eb274e9fab40b012080 100644 (file)
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
-#include <asm/io.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
+#include <asm/io.h>
 
 #include "appldata.h"
 
 
-#define MY_PRINT_NAME "appldata_mem"           /* for debug messages, etc. */
 #define P2K(x) ((x) << (PAGE_SHIFT - 10))      /* Converts #Pages to KB */
 
 /*
@@ -70,30 +69,6 @@ static struct appldata_mem_data {
 } __attribute__((packed)) appldata_mem_data;
 
 
-static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
-{
-       P_DEBUG("--- MEM - RECORD ---\n");
-       P_DEBUG("pgpgin     = %8lu KB\n", mem_data->pgpgin);
-       P_DEBUG("pgpgout    = %8lu KB\n", mem_data->pgpgout);
-       P_DEBUG("pswpin     = %8lu Pages\n", mem_data->pswpin);
-       P_DEBUG("pswpout    = %8lu Pages\n", mem_data->pswpout);
-       P_DEBUG("pgalloc    = %8lu \n", mem_data->pgalloc);
-       P_DEBUG("pgfault    = %8lu \n", mem_data->pgfault);
-       P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault);
-       P_DEBUG("sharedram  = %8lu KB\n", mem_data->sharedram);
-       P_DEBUG("totalram   = %8lu KB\n", mem_data->totalram);
-       P_DEBUG("freeram    = %8lu KB\n", mem_data->freeram);
-       P_DEBUG("totalhigh  = %8lu KB\n", mem_data->totalhigh);
-       P_DEBUG("freehigh   = %8lu KB\n", mem_data->freehigh);
-       P_DEBUG("bufferram  = %8lu KB\n", mem_data->bufferram);
-       P_DEBUG("cached     = %8lu KB\n", mem_data->cached);
-       P_DEBUG("totalswap  = %8lu KB\n", mem_data->totalswap);
-       P_DEBUG("freeswap   = %8lu KB\n", mem_data->freeswap);
-       P_DEBUG("sync_count_1 = %u\n", mem_data->sync_count_1);
-       P_DEBUG("sync_count_2 = %u\n", mem_data->sync_count_2);
-       P_DEBUG("timestamp    = %lX\n", mem_data->timestamp);
-}
-
 /*
  * appldata_get_mem_data()
  *
@@ -140,9 +115,6 @@ static void appldata_get_mem_data(void *data)
 
        mem_data->timestamp = get_clock();
        mem_data->sync_count_2++;
-#ifdef APPLDATA_DEBUG
-       appldata_debug_print(mem_data);
-#endif
 }
 
 
@@ -164,17 +136,7 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_mem_init(void)
 {
-       int rc;
-
-       P_DEBUG("sizeof(mem) = %lu\n", sizeof(struct appldata_mem_data));
-
-       rc = appldata_register_ops(&ops);
-       if (rc != 0) {
-               P_ERROR("Error registering ops, rc = %i\n", rc);
-       } else {
-               P_DEBUG("%s-ops registered!\n", ops.name);
-       }
-       return rc;
+       return appldata_register_ops(&ops);
 }
 
 /*
@@ -185,7 +147,6 @@ static int __init appldata_mem_init(void)
 static void __exit appldata_mem_exit(void)
 {
        appldata_unregister_ops(&ops);
-       P_DEBUG("%s-ops unregistered!\n", ops.name);
 }
 
 
index 4d8344336001c8d90edeb7b731fd6558a726d016..3b746556e1a39ddce7dcac254538c521b3e835a1 100644 (file)
@@ -21,9 +21,6 @@
 #include "appldata.h"
 
 
-#define MY_PRINT_NAME  "appldata_net_sum"      /* for debug messages, etc. */
-
-
 /*
  * Network data
  *
@@ -60,26 +57,6 @@ static struct appldata_net_sum_data {
 } __attribute__((packed)) appldata_net_sum_data;
 
 
-static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
-{
-       P_DEBUG("--- NET - RECORD ---\n");
-
-       P_DEBUG("nr_interfaces = %u\n", net_data->nr_interfaces);
-       P_DEBUG("rx_packets    = %8lu\n", net_data->rx_packets);
-       P_DEBUG("tx_packets    = %8lu\n", net_data->tx_packets);
-       P_DEBUG("rx_bytes      = %8lu\n", net_data->rx_bytes);
-       P_DEBUG("tx_bytes      = %8lu\n", net_data->tx_bytes);
-       P_DEBUG("rx_errors     = %8lu\n", net_data->rx_errors);
-       P_DEBUG("tx_errors     = %8lu\n", net_data->tx_errors);
-       P_DEBUG("rx_dropped    = %8lu\n", net_data->rx_dropped);
-       P_DEBUG("tx_dropped    = %8lu\n", net_data->tx_dropped);
-       P_DEBUG("collisions    = %8lu\n", net_data->collisions);
-
-       P_DEBUG("sync_count_1 = %u\n", net_data->sync_count_1);
-       P_DEBUG("sync_count_2 = %u\n", net_data->sync_count_2);
-       P_DEBUG("timestamp    = %lX\n", net_data->timestamp);
-}
-
 /*
  * appldata_get_net_sum_data()
  *
@@ -135,9 +112,6 @@ static void appldata_get_net_sum_data(void *data)
 
        net_data->timestamp = get_clock();
        net_data->sync_count_2++;
-#ifdef APPLDATA_DEBUG
-       appldata_print_debug(net_data);
-#endif
 }
 
 
@@ -159,17 +133,7 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_net_init(void)
 {
-       int rc;
-
-       P_DEBUG("sizeof(net) = %lu\n", sizeof(struct appldata_net_sum_data));
-
-       rc = appldata_register_ops(&ops);
-       if (rc != 0) {
-               P_ERROR("Error registering ops, rc = %i\n", rc);
-       } else {
-               P_DEBUG("%s-ops registered!\n", ops.name);
-       }
-       return rc;
+       return appldata_register_ops(&ops);
 }
 
 /*
@@ -180,7 +144,6 @@ static int __init appldata_net_init(void)
 static void __exit appldata_net_exit(void)
 {
        appldata_unregister_ops(&ops);
-       P_DEBUG("%s-ops unregistered!\n", ops.name);
 }
 
 
index 6b3eafe104533587e9e439a5852d5020164959ca..eb44f9f8ab917c85a4d3ea6476408b4c86bb343b 100644 (file)
@@ -89,44 +89,6 @@ static struct appldata_ops ops = {
 };
 
 
-static inline void appldata_print_debug(struct appldata_os_data *os_data)
-{
-       int a0, a1, a2, i;
-
-       P_DEBUG("--- OS - RECORD ---\n");
-       P_DEBUG("nr_threads   = %u\n", os_data->nr_threads);
-       P_DEBUG("nr_running   = %u\n", os_data->nr_running);
-       P_DEBUG("nr_iowait    = %u\n", os_data->nr_iowait);
-       P_DEBUG("avenrun(int) = %8x / %8x / %8x\n", os_data->avenrun[0],
-               os_data->avenrun[1], os_data->avenrun[2]);
-       a0 = os_data->avenrun[0];
-       a1 = os_data->avenrun[1];
-       a2 = os_data->avenrun[2];
-       P_DEBUG("avenrun(float) = %d.%02d / %d.%02d / %d.%02d\n",
-               LOAD_INT(a0), LOAD_FRAC(a0), LOAD_INT(a1), LOAD_FRAC(a1),
-               LOAD_INT(a2), LOAD_FRAC(a2));
-
-       P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus);
-       for (i = 0; i < os_data->nr_cpus; i++) {
-               P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
-                       "idle = %u, irq = %u, softirq = %u, iowait = %u, "
-                       "steal = %u\n",
-                               os_data->os_cpu[i].cpu_id,
-                               os_data->os_cpu[i].per_cpu_user,
-                               os_data->os_cpu[i].per_cpu_nice,
-                               os_data->os_cpu[i].per_cpu_system,
-                               os_data->os_cpu[i].per_cpu_idle,
-                               os_data->os_cpu[i].per_cpu_irq,
-                               os_data->os_cpu[i].per_cpu_softirq,
-                               os_data->os_cpu[i].per_cpu_iowait,
-                               os_data->os_cpu[i].per_cpu_steal);
-       }
-
-       P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1);
-       P_DEBUG("sync_count_2 = %u\n", os_data->sync_count_2);
-       P_DEBUG("timestamp    = %lX\n", os_data->timestamp);
-}
-
 /*
  * appldata_get_os_data()
  *
@@ -180,13 +142,10 @@ static void appldata_get_os_data(void *data)
                                           APPLDATA_START_INTERVAL_REC,
                                           (unsigned long) ops.data, new_size,
                                           ops.mod_lvl);
-                       if (rc != 0) {
+                       if (rc != 0)
                                P_ERROR("os: START NEW DIAG 0xDC failed, "
                                        "return code: %d, new size = %i\n", rc,
                                        new_size);
-                               P_INFO("os: stopping old record now\n");
-                       } else
-                               P_INFO("os: new record size = %i\n", new_size);
 
                        rc = appldata_diag(APPLDATA_RECORD_OS_ID,
                                           APPLDATA_STOP_REC,
@@ -204,9 +163,6 @@ static void appldata_get_os_data(void *data)
        }
        os_data->timestamp = get_clock();
        os_data->sync_count_2++;
-#ifdef APPLDATA_DEBUG
-       appldata_print_debug(os_data);
-#endif
 }
 
 
@@ -227,12 +183,9 @@ static int __init appldata_os_init(void)
                rc = -ENOMEM;
                goto out;
        }
-       P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size,
-               sizeof(struct appldata_os_per_cpu));
 
        appldata_os_data = kzalloc(max_size, GFP_DMA);
        if (appldata_os_data == NULL) {
-               P_ERROR("No memory for %s!\n", ops.name);
                rc = -ENOMEM;
                goto out;
        }
@@ -240,17 +193,12 @@ static int __init appldata_os_init(void)
        appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
        appldata_os_data->cpu_offset   = offsetof(struct appldata_os_data,
                                                        os_cpu);
-       P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset);
 
        ops.data = appldata_os_data;
        ops.callback  = &appldata_get_os_data;
        rc = appldata_register_ops(&ops);
-       if (rc != 0) {
-               P_ERROR("Error registering ops, rc = %i\n", rc);
+       if (rc != 0)
                kfree(appldata_os_data);
-       } else {
-               P_DEBUG("%s-ops registered!\n", ops.name);
-       }
 out:
        return rc;
 }
@@ -264,7 +212,6 @@ static void __exit appldata_os_exit(void)
 {
        appldata_unregister_ops(&ops);
        kfree(appldata_os_data);
-       P_DEBUG("%s-ops unregistered!\n", ops.name);
 }
 
 
index 9992f95ef992a0276fa0878ddeb3282a8a224ca3..0ef9829f2ad69e2e15b743ac1582858a48124067 100644 (file)
@@ -296,6 +296,10 @@ static inline int crypt_s390_func_available(int func)
        unsigned char status[16];
        int ret;
 
+       /* check if CPACF facility (bit 17) is available */
+       if (!(stfl() & 1ULL << (31 - 17)))
+               return 0;
+
        switch (func & CRYPT_S390_OP_MASK) {
        case CRYPT_S390_KM:
                ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
index 0cfefddd83755366fee0dae7634ccca6342b21dd..6a4300b3ff52023f68ab2c614a117084cf3a0015 100644 (file)
@@ -185,11 +185,8 @@ static int __init prng_init(void)
        prng_seed(16);
 
        ret = misc_register(&prng_dev);
-       if (ret) {
-               printk(KERN_WARNING
-                      "Could not register misc device for PRNG.\n");
+       if (ret)
                goto out_buf;
-       }
        return 0;
 
 out_buf:
index 4b010ff814c9caa3f439cb7e849aa8c501bdace1..7383781f3e6a60ba3c632b1f0d3b26c7800c6ecf 100644 (file)
@@ -150,33 +150,24 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
                              unsigned long nr_segs, loff_t offset)
 {
        char *data;
-       size_t len;
+       ssize_t ret;
        struct file *filp = iocb->ki_filp;
        /* XXX: temporary */
        char __user *buf = iov[0].iov_base;
        size_t count = iov[0].iov_len;
 
-       if (nr_segs != 1) {
-               count = -EINVAL;
-               goto out;
-       }
+       if (nr_segs != 1)
+               return -EINVAL;
 
        data = filp->private_data;
-       len = strlen(data);
-       if (offset > len) {
-               count = 0;
-               goto out;
-       }
-       if (count > len - offset)
-               count = len - offset;
-       if (copy_to_user(buf, data + offset, count)) {
-               count = -EFAULT;
-               goto out;
-       }
-       iocb->ki_pos += count;
+       ret = simple_read_from_buffer(buf, count, &offset, data, strlen(data));
+       if (ret <= 0)
+               return ret;
+
+       iocb->ki_pos += ret;
        file_accessed(filp);
-out:
-       return count;
+
+       return ret;
 }
 static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
                              unsigned long nr_segs, loff_t offset)
index 6302f508258866120b2625198ec411c8f455202c..50f657e773449e29d1fa2d64ad5c8e87047f9bd2 100644 (file)
@@ -7,9 +7,14 @@
 #
 CFLAGS_smp.o   := -Wno-nonnull
 
+#
+# Pass UTS_MACHINE for user_regset definition
+#
+CFLAGS_ptrace.o                += -DUTS_MACHINE='"$(UTS_MACHINE)"'
+
 obj-y  :=  bitmap.o traps.o time.o process.o base.o early.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-           s390_ext.o debug.o irq.o ipl.o dis.o diag.o
+           s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o
 
 obj-y  += $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y  += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
@@ -23,7 +28,7 @@ obj-$(CONFIG_AUDIT)           += audit.o
 compat-obj-$(CONFIG_AUDIT)     += compat_audit.o
 obj-$(CONFIG_COMPAT)           += compat_linux.o compat_signal.o \
                                        compat_wrapper.o compat_exec_domain.o \
-                                       binfmt_elf32.o $(compat-obj-y)
+                                       $(compat-obj-y)
 
 obj-$(CONFIG_VIRT_TIMER)       += vtime.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c
deleted file mode 100644 (file)
index 3e1c315..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Support for 32-bit Linux for S390 ELF binaries.
- *
- * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Gerhard Tonn (ton@de.ibm.com)
- *
- * Heavily inspired by the 32-bit Sparc compat code which is
- * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek   (jj@ultra.linux.cz)
- */
-
-#define __ASMS390_ELF_H
-
-#include <linux/time.h>
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS      ELFCLASS32
-#define ELF_DATA       ELFDATA2MSB
-#define ELF_ARCH       EM_S390
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) \
-       (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
-         && (x)->e_ident[EI_CLASS] == ELF_CLASS)
-
-/* ELF register definitions */
-#define NUM_GPRS      16
-#define NUM_FPRS      16
-#define NUM_ACRS      16    
-
-/* For SVR4/S390 the function pointer to be registered with `atexit` is
-   passed in R14. */
-#define ELF_PLAT_INIT(_r, load_addr) \
-       do { \
-               _r->gprs[14] = 0; \
-       } while(0)
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE       4096
-
-/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
-   use of this is to invoke "./ld.so someprog" to test out a new version of
-   the loader.  We need to make sure that it is out of the way of the program
-   that it will "exec", and that there is sufficient room for the brk.  */
-
-#define ELF_ET_DYN_BASE         (TASK_SIZE / 3 * 2)
-
-/* Wow, the "main" arch needs arch dependent functions too.. :) */
-
-/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
-   now struct_user_regs, they are different) */
-
-#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg);
-
-#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs32(tsk, regs)
-
-#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
-
-/* This yields a mask that user programs can use to figure out what
-   instruction set this CPU supports. */
-
-#define ELF_HWCAP (0)
-
-/* This yields a string that ld.so will use to load implementation
-   specific libraries for optimization.  This is more specific in
-   intent than poking at uname or /proc/cpuinfo.
-
-   For the moment, we have only optimizations for the Intel generations,
-   but that could change... */
-
-#define ELF_PLATFORM (NULL)
-
-#define SET_PERSONALITY(ex, ibcs2)                     \
-do {                                                   \
-       if (ibcs2)                                      \
-               set_personality(PER_SVR4);              \
-       else if (current->personality != PER_LINUX32)   \
-               set_personality(PER_LINUX);             \
-       set_thread_flag(TIF_31BIT);                     \
-} while (0)
-
-#include "compat_linux.h"
-
-typedef _s390_fp_regs32 elf_fpregset_t;
-
-typedef struct
-{
-       
-       _psw_t32        psw;
-       __u32           gprs[__NUM_GPRS]; 
-       __u32           acrs[__NUM_ACRS]; 
-       __u32           orig_gpr2;
-} s390_regs32;
-typedef s390_regs32 elf_gregset_t;
-
-static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs)
-{
-       int i;
-
-       memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
-       memcpy(&regs->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
-       for (i = 0; i < NUM_GPRS; i++)
-               regs->gprs[i] = ptregs->gprs[i];
-       save_access_regs(regs->acrs);
-       regs->orig_gpr2 = ptregs->orig_gpr2;
-       return 1;
-}
-
-static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs)
-{
-       struct pt_regs *ptregs = task_pt_regs(tsk);
-       int i;
-
-       memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
-       memcpy(&regs->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
-       for (i = 0; i < NUM_GPRS; i++)
-               regs->gprs[i] = ptregs->gprs[i];
-       memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
-       regs->orig_gpr2 = ptregs->orig_gpr2;
-       return 1;
-}
-
-static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
-{
-       if (tsk == current)
-               save_fp_regs((s390_fp_regs *) fpregs);
-       else
-               memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
-       return 1;
-}
-
-#include <asm/processor.h>
-#include <asm/pgalloc.h>
-#include <linux/module.h>
-#include <linux/elfcore.h>
-#include <linux/binfmts.h>
-#include <linux/compat.h>
-
-#define elf_prstatus elf_prstatus32
-struct elf_prstatus32
-{
-       struct elf_siginfo pr_info;     /* Info associated with signal */
-       short   pr_cursig;              /* Current signal */
-       u32     pr_sigpend;     /* Set of pending signals */
-       u32     pr_sighold;     /* Set of held signals */
-       pid_t   pr_pid;
-       pid_t   pr_ppid;
-       pid_t   pr_pgrp;
-       pid_t   pr_sid;
-       struct compat_timeval pr_utime; /* User time */
-       struct compat_timeval pr_stime; /* System time */
-       struct compat_timeval pr_cutime;        /* Cumulative user time */
-       struct compat_timeval pr_cstime;        /* Cumulative system time */
-       elf_gregset_t pr_reg;   /* GP registers */
-       int pr_fpvalid;         /* True if math co-processor being used.  */
-};
-
-#define elf_prpsinfo elf_prpsinfo32
-struct elf_prpsinfo32
-{
-       char    pr_state;       /* numeric process state */
-       char    pr_sname;       /* char for pr_state */
-       char    pr_zomb;        /* zombie */
-       char    pr_nice;        /* nice val */
-       u32     pr_flag;        /* flags */
-       u16     pr_uid;
-       u16     pr_gid;
-       pid_t   pr_pid, pr_ppid, pr_pgrp, pr_sid;
-       /* Lots missing */
-       char    pr_fname[16];   /* filename of executable */
-       char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
-};
-
-#include <linux/highuid.h>
-
-/*
-#define init_elf_binfmt init_elf32_binfmt
-*/
-
-#undef start_thread
-#define start_thread                    start_thread31 
-
-static inline void start_thread31(struct pt_regs *regs, unsigned long new_psw,
-                                 unsigned long new_stackp)
-{
-       set_fs(USER_DS);
-       regs->psw.mask  = psw_user32_bits;
-       regs->psw.addr  = new_psw;
-       regs->gprs[15]  = new_stackp;
-       crst_table_downgrade(current->mm, 1UL << 31);
-}
-
-MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
-                   " Copyright 2000 IBM Corporation"); 
-MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
-
-#undef MODULE_DESCRIPTION
-#undef MODULE_AUTHOR
-
-#undef cputime_to_timeval
-#define cputime_to_timeval cputime_to_compat_timeval
-static inline void
-cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
-{
-       value->tv_usec = cputime % 1000000;
-       value->tv_sec = cputime / 1000000;
-}
-
-#include "../../../fs/binfmt_elf.c"
-
index 419aef913ee1233c0ab6af25c81ef21a1a22061f..cde81fa64f89bf17bc586dce3f973e77f55985e8 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _PTRACE32_H
 #define _PTRACE32_H
 
-#include "compat_linux.h"  /* needed for _psw_t32 */
+#include "compat_linux.h"  /* needed for psw_compat_t */
 
 typedef struct {
        __u32 cr[3];
@@ -38,7 +38,7 @@ typedef struct {
 
 struct user_regs_struct32
 {
-       _psw_t32 psw;
+       psw_compat_t psw;
        u32 gprs[NUM_GPRS];
        u32 acrs[NUM_ACRS];
        u32 orig_gpr2;
index c93d1296cc0a7eeff66feaa20e9666bb5e31b6fa..d80fcd4a7fe14210aac75d33d824fa9c6eb1c4a7 100644 (file)
@@ -1079,7 +1079,6 @@ __init debug_init(void)
        s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
        mutex_lock(&debug_mutex);
        debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
-       printk(KERN_INFO "debug: Initialization complete\n");
        initialized = 1;
        mutex_unlock(&debug_mutex);
 
@@ -1193,7 +1192,6 @@ debug_get_uint(char *buf)
        for(; isspace(*buf); buf++);
        rc = simple_strtoul(buf, &buf, 10);
        if(*buf){
-               printk("debug: no integer specified!\n");
                rc = -EINVAL;
        }
        return rc;
@@ -1340,19 +1338,12 @@ static void debug_flush(debug_info_t* id, int area)
                                memset(id->areas[i][j], 0, PAGE_SIZE);
                        }
                }
-                printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
         } else if(area >= 0 && area < id->nr_areas) {
                 id->active_entries[area] = 0;
                id->active_pages[area] = 0;
                for(i = 0; i < id->pages_per_area; i++) {
                        memset(id->areas[area][i],0,PAGE_SIZE);
                }
-                printk(KERN_INFO "debug: %s: area %i has been flushed\n",
-                        id->name, area);
-        } else {
-                printk(KERN_INFO
-                      "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
-                        id->name, area, 0, id->nr_areas-1);
         }
         spin_unlock_irqrestore(&id->lock,flags);
 }
index d0e09684b9ce8c4f0924017a51f86e12ddec93d5..2a2ca268b1dd6e6bc38115496674ee965f8ef29a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/pfn.h>
 #include <linux/uaccess.h>
+#include <asm/ebcdic.h>
 #include <asm/ipl.h>
 #include <asm/lowcore.h>
 #include <asm/processor.h>
 /*
  * Create a Kernel NSS if the SAVESYS= parameter is defined
  */
-#define DEFSYS_CMD_SIZE                96
+#define DEFSYS_CMD_SIZE                128
 #define SAVESYS_CMD_SIZE       32
 
 char kernel_nss_name[NSS_NAME_SIZE + 1];
 
+static void __init setup_boot_command_line(void);
+
+
 #ifdef CONFIG_SHARED_KERNEL
+int __init savesys_ipl_nss(char *cmd, const int cmdlen);
+
+asm(
+       "       .section .init.text,\"ax\",@progbits\n"
+       "       .align  4\n"
+       "       .type   savesys_ipl_nss, @function\n"
+       "savesys_ipl_nss:\n"
+#ifdef CONFIG_64BIT
+       "       stmg    6,15,48(15)\n"
+       "       lgr     14,3\n"
+       "       sam31\n"
+       "       diag    2,14,0x8\n"
+       "       sam64\n"
+       "       lgr     2,14\n"
+       "       lmg     6,15,48(15)\n"
+#else
+       "       stm     6,15,24(15)\n"
+       "       lr      14,3\n"
+       "       diag    2,14,0x8\n"
+       "       lr      2,14\n"
+       "       lm      6,15,24(15)\n"
+#endif
+       "       br      14\n"
+       "       .size   savesys_ipl_nss, .-savesys_ipl_nss\n");
+
 static noinline __init void create_kernel_nss(void)
 {
        unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
@@ -39,6 +68,7 @@ static noinline __init void create_kernel_nss(void)
        unsigned int sinitrd_pfn, einitrd_pfn;
 #endif
        int response;
+       size_t len;
        char *savesys_ptr;
        char upper_command_line[COMMAND_LINE_SIZE];
        char defsys_cmd[DEFSYS_CMD_SIZE];
@@ -49,8 +79,8 @@ static noinline __init void create_kernel_nss(void)
                return;
 
        /* Convert COMMAND_LINE to upper case */
-       for (i = 0; i < strlen(COMMAND_LINE); i++)
-               upper_command_line[i] = toupper(COMMAND_LINE[i]);
+       for (i = 0; i < strlen(boot_command_line); i++)
+               upper_command_line[i] = toupper(boot_command_line[i]);
 
        savesys_ptr = strstr(upper_command_line, "SAVESYS=");
 
@@ -83,7 +113,8 @@ static noinline __init void create_kernel_nss(void)
        }
 #endif
 
-       sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
+       sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
+               defsys_cmd, min_size);
        sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
                kernel_nss_name, kernel_nss_name);
 
@@ -94,13 +125,24 @@ static noinline __init void create_kernel_nss(void)
                return;
        }
 
-       __cpcmd(savesys_cmd, NULL, 0, &response);
+       len = strlen(savesys_cmd);
+       ASCEBC(savesys_cmd, len);
+       response = savesys_ipl_nss(savesys_cmd, len);
 
-       if (response != strlen(savesys_cmd)) {
+       /* On success: response is equal to the command size,
+        *             max SAVESYS_CMD_SIZE
+        * On error: response contains the numeric portion of cp error message.
+        *           for SAVESYS it will be >= 263
+        */
+       if (response > SAVESYS_CMD_SIZE) {
                kernel_nss_name[0] = '\0';
                return;
        }
 
+       /* re-setup boot command line with new ipl vm parms */
+       ipl_update_parameters();
+       setup_boot_command_line();
+
        ipl_flags = IPL_NSS_VALID;
 }
 
@@ -141,109 +183,11 @@ static noinline __init void detect_machine_type(void)
        if (cpuinfo->cpu_id.version == 0xff)
                machine_flags |= MACHINE_FLAG_VM;
 
-       /* Running on a P/390 ? */
-       if (cpuinfo->cpu_id.machine == 0x7490)
-               machine_flags |= MACHINE_FLAG_P390;
-
        /* Running under KVM ? */
        if (cpuinfo->cpu_id.version == 0xfe)
                machine_flags |= MACHINE_FLAG_KVM;
 }
 
-#ifdef CONFIG_64BIT
-static noinline __init int memory_fast_detect(void)
-{
-       unsigned long val0 = 0;
-       unsigned long val1 = 0xc;
-       int ret = -ENOSYS;
-
-       if (ipl_flags & IPL_NSS_VALID)
-               return -ENOSYS;
-
-       asm volatile(
-               "       diag    %1,%2,0x260\n"
-               "0:     lhi     %0,0\n"
-               "1:\n"
-               EX_TABLE(0b,1b)
-               : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
-
-       if (ret || val0 != val1)
-               return -ENOSYS;
-
-       memory_chunk[0].size = val0 + 1;
-       return 0;
-}
-#else
-static inline int memory_fast_detect(void)
-{
-       return -ENOSYS;
-}
-#endif
-
-static inline __init unsigned long __tprot(unsigned long addr)
-{
-       int cc = -1;
-
-       asm volatile(
-               "       tprot   0(%1),0\n"
-               "0:     ipm     %0\n"
-               "       srl     %0,28\n"
-               "1:\n"
-               EX_TABLE(0b,1b)
-               : "+d" (cc) : "a" (addr) : "cc");
-       return (unsigned long)cc;
-}
-
-/* Checking memory in 128KB increments. */
-#define CHUNK_INCR     (1UL << 17)
-#define ADDR2G         (1UL << 31)
-
-static noinline __init void find_memory_chunks(unsigned long memsize)
-{
-       unsigned long addr = 0, old_addr = 0;
-       unsigned long old_cc = CHUNK_READ_WRITE;
-       unsigned long cc;
-       int chunk = 0;
-
-       while (chunk < MEMORY_CHUNKS) {
-               cc = __tprot(addr);
-               while (cc == old_cc) {
-                       addr += CHUNK_INCR;
-                       if (memsize && addr >= memsize)
-                               break;
-#ifndef CONFIG_64BIT
-                       if (addr == ADDR2G)
-                               break;
-#endif
-                       cc = __tprot(addr);
-               }
-
-               if (old_addr != addr &&
-                   (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
-                       memory_chunk[chunk].addr = old_addr;
-                       memory_chunk[chunk].size = addr - old_addr;
-                       memory_chunk[chunk].type = old_cc;
-                       chunk++;
-               }
-
-               old_addr = addr;
-               old_cc = cc;
-
-#ifndef CONFIG_64BIT
-               if (addr == ADDR2G)
-                       break;
-#endif
-               /*
-                * Finish memory detection at the first hole
-                * if storage size is unknown.
-                */
-               if (cc == -1UL && !memsize)
-                       break;
-               if (memsize && addr >= memsize)
-                       break;
-       }
-}
-
 static __init void early_pgm_check_handler(void)
 {
        unsigned long addr;
@@ -380,23 +324,61 @@ static __init void detect_machine_facilities(void)
 #endif
 }
 
+static __init void rescue_initrd(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       /*
+        * Move the initrd right behind the bss section in case it starts
+        * within the bss section. So we don't overwrite it when the bss
+        * section gets cleared.
+        */
+       if (!INITRD_START || !INITRD_SIZE)
+               return;
+       if (INITRD_START >= (unsigned long) __bss_stop)
+               return;
+       memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE);
+       INITRD_START = (unsigned long) __bss_stop;
+#endif
+}
+
+/* Set up boot command line */
+static void __init setup_boot_command_line(void)
+{
+       char *parm = NULL;
+
+       /* copy arch command line */
+       strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
+       boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;
+
+       /* append IPL PARM data to the boot command line */
+       if (MACHINE_IS_VM) {
+               parm = boot_command_line + strlen(boot_command_line);
+               *parm++ = ' ';
+               get_ipl_vmparm(parm);
+               if (parm[0] == '=')
+                       memmove(boot_command_line, parm + 1, strlen(parm));
+       }
+}
+
+
 /*
  * Save ipl parameters, clear bss memory, initialize storage keys
  * and create a kernel NSS at startup if the SAVESYS= parm is defined
  */
 void __init startup_init(void)
 {
-       unsigned long long memsize;
-
        ipl_save_parameters();
+       rescue_initrd();
        clear_bss_section();
        init_kernel_storage_key();
        lockdep_init();
        lockdep_off();
-       detect_machine_type();
-       create_kernel_nss();
        sort_main_extable();
        setup_lowcore_early();
+       detect_machine_type();
+       ipl_update_parameters();
+       setup_boot_command_line();
+       create_kernel_nss();
        detect_mvpg();
        detect_ieee();
        detect_csp();
@@ -404,18 +386,7 @@ void __init startup_init(void)
        detect_diag44();
        detect_machine_facilities();
        setup_hpage();
-       sclp_read_info_early();
        sclp_facilities_detect();
-       memsize = sclp_memory_detect();
-#ifndef CONFIG_64BIT
-       /*
-        * Can't deal with more than 2G in 31 bit addressing mode, so
-        * limit the value in order to avoid strange side effects.
-        */
-       if (memsize > ADDR2G)
-               memsize = ADDR2G;
-#endif
-       if (memory_fast_detect() < 0)
-               find_memory_chunks((unsigned long) memsize);
+       detect_memory_layout(memory_chunk);
        lockdep_on();
 }
index 532542447d661a34537e42ff69571616d8874865..54b2779b5e2fa49b45cecfb929b0ec6fdba9c3ae 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/ctype.h>
+#include <linux/fs.h>
 #include <asm/ipl.h>
 #include <asm/smp.h>
 #include <asm/setup.h>
@@ -22,6 +23,7 @@
 #include <asm/ebcdic.h>
 #include <asm/reset.h>
 #include <asm/sclp.h>
+#include <asm/setup.h>
 
 #define IPL_PARM_BLOCK_VERSION 0
 
@@ -121,6 +123,7 @@ enum ipl_method {
        REIPL_METHOD_FCP_RO_VM,
        REIPL_METHOD_FCP_DUMP,
        REIPL_METHOD_NSS,
+       REIPL_METHOD_NSS_DIAG,
        REIPL_METHOD_DEFAULT,
 };
 
@@ -134,14 +137,15 @@ enum dump_method {
 
 static int diag308_set_works = 0;
 
+static struct ipl_parameter_block ipl_block;
+
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
 
 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_ccw;
-
-static char reipl_nss_name[NSS_NAME_SIZE + 1];
+static struct ipl_parameter_block *reipl_block_nss;
 
 static int dump_capabilities = DUMP_TYPE_NONE;
 static enum dump_type dump_type = DUMP_TYPE_NONE;
@@ -263,6 +267,56 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
 
 static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
 
+/* VM IPL PARM routines */
+static void reipl_get_ascii_vmparm(char *dest,
+                                  const struct ipl_parameter_block *ipb)
+{
+       int i;
+       int len = 0;
+       char has_lowercase = 0;
+
+       if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
+           (ipb->ipl_info.ccw.vm_parm_len > 0)) {
+
+               len = ipb->ipl_info.ccw.vm_parm_len;
+               memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
+               /* If at least one character is lowercase, we assume mixed
+                * case; otherwise we convert everything to lowercase.
+                */
+               for (i = 0; i < len; i++)
+                       if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */
+                           (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */
+                           (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */
+                               has_lowercase = 1;
+                               break;
+                       }
+               if (!has_lowercase)
+                       EBC_TOLOWER(dest, len);
+               EBCASC(dest, len);
+       }
+       dest[len] = 0;
+}
+
+void get_ipl_vmparm(char *dest)
+{
+       if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
+               reipl_get_ascii_vmparm(dest, &ipl_block);
+       else
+               dest[0] = 0;
+}
+
+static ssize_t ipl_vm_parm_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *page)
+{
+       char parm[DIAG308_VMPARM_SIZE + 1] = {};
+
+       get_ipl_vmparm(parm);
+       return sprintf(page, "%s\n", parm);
+}
+
+static struct kobj_attribute sys_ipl_vm_parm_attr =
+       __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
+
 static ssize_t sys_ipl_device_show(struct kobject *kobj,
                                   struct kobj_attribute *attr, char *page)
 {
@@ -285,14 +339,8 @@ static struct kobj_attribute sys_ipl_device_attr =
 static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
                                  char *buf, loff_t off, size_t count)
 {
-       unsigned int size = IPL_PARMBLOCK_SIZE;
-
-       if (off > size)
-               return 0;
-       if (off + count > size)
-               count = size - off;
-       memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
-       return count;
+       return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START,
+                                       IPL_PARMBLOCK_SIZE);
 }
 
 static struct bin_attribute ipl_parameter_attr = {
@@ -310,12 +358,7 @@ static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *att
        unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
        void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
 
-       if (off > size)
-               return 0;
-       if (off + count > size)
-               count = size - off;
-       memcpy(buf, scp_data + off, count);
-       return count;
+       return memory_read_from_buffer(buf, count, &off, scp_data, size);
 }
 
 static struct bin_attribute ipl_scp_data_attr = {
@@ -370,15 +413,27 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
 static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
        __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
 
-static struct attribute *ipl_ccw_attrs[] = {
+static struct attribute *ipl_ccw_attrs_vm[] = {
        &sys_ipl_type_attr.attr,
        &sys_ipl_device_attr.attr,
        &sys_ipl_ccw_loadparm_attr.attr,
+       &sys_ipl_vm_parm_attr.attr,
        NULL,
 };
 
-static struct attribute_group ipl_ccw_attr_group = {
-       .attrs = ipl_ccw_attrs,
+static struct attribute *ipl_ccw_attrs_lpar[] = {
+       &sys_ipl_type_attr.attr,
+       &sys_ipl_device_attr.attr,
+       &sys_ipl_ccw_loadparm_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ipl_ccw_attr_group_vm = {
+       .attrs = ipl_ccw_attrs_vm,
+};
+
+static struct attribute_group ipl_ccw_attr_group_lpar = {
+       .attrs = ipl_ccw_attrs_lpar
 };
 
 /* NSS ipl device attributes */
@@ -388,6 +443,8 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
 static struct attribute *ipl_nss_attrs[] = {
        &sys_ipl_type_attr.attr,
        &sys_ipl_nss_name_attr.attr,
+       &sys_ipl_ccw_loadparm_attr.attr,
+       &sys_ipl_vm_parm_attr.attr,
        NULL,
 };
 
@@ -450,7 +507,12 @@ static int __init ipl_init(void)
        }
        switch (ipl_info.type) {
        case IPL_TYPE_CCW:
-               rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
+               if (MACHINE_IS_VM)
+                       rc = sysfs_create_group(&ipl_kset->kobj,
+                                               &ipl_ccw_attr_group_vm);
+               else
+                       rc = sysfs_create_group(&ipl_kset->kobj,
+                                               &ipl_ccw_attr_group_lpar);
                break;
        case IPL_TYPE_FCP:
        case IPL_TYPE_FCP_DUMP:
@@ -481,6 +543,83 @@ static struct shutdown_action __refdata ipl_action = {
  * reipl shutdown action: Reboot Linux on shutdown.
  */
 
+/* VM IPL PARM attributes */
+static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
+                                         char *page)
+{
+       char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
+
+       reipl_get_ascii_vmparm(vmparm, ipb);
+       return sprintf(page, "%s\n", vmparm);
+}
+
+static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
+                                         size_t vmparm_max,
+                                         const char *buf, size_t len)
+{
+       int i, ip_len;
+
+       /* ignore trailing newline */
+       ip_len = len;
+       if ((len > 0) && (buf[len - 1] == '\n'))
+               ip_len--;
+
+       if (ip_len > vmparm_max)
+               return -EINVAL;
+
+       /* parm is used to store kernel options, check for common chars */
+       for (i = 0; i < ip_len; i++)
+               if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i])))
+                       return -EINVAL;
+
+       memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
+       ipb->ipl_info.ccw.vm_parm_len = ip_len;
+       if (ip_len > 0) {
+               ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
+               memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len);
+               ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len);
+       } else {
+               ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID;
+       }
+
+       return len;
+}
+
+/* NSS wrapper */
+static ssize_t reipl_nss_vmparm_show(struct kobject *kobj,
+                                    struct kobj_attribute *attr, char *page)
+{
+       return reipl_generic_vmparm_show(reipl_block_nss, page);
+}
+
+static ssize_t reipl_nss_vmparm_store(struct kobject *kobj,
+                                     struct kobj_attribute *attr,
+                                     const char *buf, size_t len)
+{
+       return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len);
+}
+
+/* CCW wrapper */
+static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj,
+                                    struct kobj_attribute *attr, char *page)
+{
+       return reipl_generic_vmparm_show(reipl_block_ccw, page);
+}
+
+static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
+                                     struct kobj_attribute *attr,
+                                     const char *buf, size_t len)
+{
+       return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len);
+}
+
+static struct kobj_attribute sys_reipl_nss_vmparm_attr =
+       __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
+                                       reipl_nss_vmparm_store);
+static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
+       __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
+                                       reipl_ccw_vmparm_store);
+
 /* FCP reipl device attributes */
 
 DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
@@ -513,27 +652,26 @@ static struct attribute_group reipl_fcp_attr_group = {
 DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
        reipl_block_ccw->ipl_info.ccw.devno);
 
-static void reipl_get_ascii_loadparm(char *loadparm)
+static void reipl_get_ascii_loadparm(char *loadparm,
+                                    struct ipl_parameter_block *ibp)
 {
-       memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
-              LOADPARM_LEN);
+       memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN);
        EBCASC(loadparm, LOADPARM_LEN);
        loadparm[LOADPARM_LEN] = 0;
        strstrip(loadparm);
 }
 
-static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
-                                      struct kobj_attribute *attr, char *page)
+static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
+                                          char *page)
 {
        char buf[LOADPARM_LEN + 1];
 
-       reipl_get_ascii_loadparm(buf);
+       reipl_get_ascii_loadparm(buf, ipb);
        return sprintf(page, "%s\n", buf);
 }
 
-static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
-                                       struct kobj_attribute *attr,
-                                       const char *buf, size_t len)
+static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
+                                           const char *buf, size_t len)
 {
        int i, lp_len;
 
@@ -552,35 +690,128 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
                return -EINVAL;
        }
        /* initialize loadparm with blanks */
-       memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN);
+       memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN);
        /* copy and convert to ebcdic */
-       memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
-       ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
+       memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len);
+       ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN);
        return len;
 }
 
+/* NSS wrapper */
+static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr, char *page)
+{
+       return reipl_generic_loadparm_show(reipl_block_nss, page);
+}
+
+static ssize_t reipl_nss_loadparm_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t len)
+{
+       return reipl_generic_loadparm_store(reipl_block_nss, buf, len);
+}
+
+/* CCW wrapper */
+static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr, char *page)
+{
+       return reipl_generic_loadparm_show(reipl_block_ccw, page);
+}
+
+static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t len)
+{
+       return reipl_generic_loadparm_store(reipl_block_ccw, buf, len);
+}
+
 static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
-       __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
-              reipl_ccw_loadparm_store);
+       __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
+                                           reipl_ccw_loadparm_store);
 
-static struct attribute *reipl_ccw_attrs[] = {
+static struct attribute *reipl_ccw_attrs_vm[] = {
        &sys_reipl_ccw_device_attr.attr,
        &sys_reipl_ccw_loadparm_attr.attr,
+       &sys_reipl_ccw_vmparm_attr.attr,
        NULL,
 };
 
-static struct attribute_group reipl_ccw_attr_group = {
+static struct attribute *reipl_ccw_attrs_lpar[] = {
+       &sys_reipl_ccw_device_attr.attr,
+       &sys_reipl_ccw_loadparm_attr.attr,
+       NULL,
+};
+
+static struct attribute_group reipl_ccw_attr_group_vm = {
+       .name  = IPL_CCW_STR,
+       .attrs = reipl_ccw_attrs_vm,
+};
+
+static struct attribute_group reipl_ccw_attr_group_lpar = {
        .name  = IPL_CCW_STR,
-       .attrs = reipl_ccw_attrs,
+       .attrs = reipl_ccw_attrs_lpar,
 };
 
 
 /* NSS reipl device attributes */
+static void reipl_get_ascii_nss_name(char *dst,
+                                    struct ipl_parameter_block *ipb)
+{
+       memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
+       EBCASC(dst, NSS_NAME_SIZE);
+       dst[NSS_NAME_SIZE] = 0;
+}
+
+static ssize_t reipl_nss_name_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *page)
+{
+       char nss_name[NSS_NAME_SIZE + 1] = {};
 
-DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
+       reipl_get_ascii_nss_name(nss_name, reipl_block_nss);
+       return sprintf(page, "%s\n", nss_name);
+}
+
+static ssize_t reipl_nss_name_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buf, size_t len)
+{
+       int nss_len;
+
+       /* ignore trailing newline */
+       nss_len = len;
+       if ((len > 0) && (buf[len - 1] == '\n'))
+               nss_len--;
+
+       if (nss_len > NSS_NAME_SIZE)
+               return -EINVAL;
+
+       memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE);
+       if (nss_len > 0) {
+               reipl_block_nss->ipl_info.ccw.vm_flags |=
+                       DIAG308_VM_FLAGS_NSS_VALID;
+               memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len);
+               ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
+               EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len);
+       } else {
+               reipl_block_nss->ipl_info.ccw.vm_flags &=
+                       ~DIAG308_VM_FLAGS_NSS_VALID;
+       }
+
+       return len;
+}
+
+static struct kobj_attribute sys_reipl_nss_name_attr =
+       __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
+                                       reipl_nss_name_store);
+
+static struct kobj_attribute sys_reipl_nss_loadparm_attr =
+       __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
+                                           reipl_nss_loadparm_store);
 
 static struct attribute *reipl_nss_attrs[] = {
        &sys_reipl_nss_name_attr.attr,
+       &sys_reipl_nss_loadparm_attr.attr,
+       &sys_reipl_nss_vmparm_attr.attr,
        NULL,
 };
 
@@ -617,7 +848,10 @@ static int reipl_set_type(enum ipl_type type)
                reipl_method = REIPL_METHOD_FCP_DUMP;
                break;
        case IPL_TYPE_NSS:
-               reipl_method = REIPL_METHOD_NSS;
+               if (diag308_set_works)
+                       reipl_method = REIPL_METHOD_NSS_DIAG;
+               else
+                       reipl_method = REIPL_METHOD_NSS;
                break;
        case IPL_TYPE_UNKNOWN:
                reipl_method = REIPL_METHOD_DEFAULT;
@@ -655,11 +889,38 @@ static struct kobj_attribute reipl_type_attr =
 
 static struct kset *reipl_kset;
 
+static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
+                          const enum ipl_method m)
+{
+       char loadparm[LOADPARM_LEN + 1] = {};
+       char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
+       char nss_name[NSS_NAME_SIZE + 1] = {};
+       size_t pos = 0;
+
+       reipl_get_ascii_loadparm(loadparm, ipb);
+       reipl_get_ascii_nss_name(nss_name, ipb);
+       reipl_get_ascii_vmparm(vmparm, ipb);
+
+       switch (m) {
+       case REIPL_METHOD_CCW_VM:
+               pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno);
+               break;
+       case REIPL_METHOD_NSS:
+               pos = sprintf(dst, "IPL %s", nss_name);
+               break;
+       default:
+               break;
+       }
+       if (strlen(loadparm) > 0)
+               pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm);
+       if (strlen(vmparm) > 0)
+               sprintf(dst + pos, " PARM %s", vmparm);
+}
+
 static void reipl_run(struct shutdown_trigger *trigger)
 {
        struct ccw_dev_id devid;
-       static char buf[100];
-       char loadparm[LOADPARM_LEN + 1];
+       static char buf[128];
 
        switch (reipl_method) {
        case REIPL_METHOD_CCW_CIO:
@@ -668,13 +929,7 @@ static void reipl_run(struct shutdown_trigger *trigger)
                reipl_ccw_dev(&devid);
                break;
        case REIPL_METHOD_CCW_VM:
-               reipl_get_ascii_loadparm(loadparm);
-               if (strlen(loadparm) == 0)
-                       sprintf(buf, "IPL %X CLEAR",
-                               reipl_block_ccw->ipl_info.ccw.devno);
-               else
-                       sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
-                               reipl_block_ccw->ipl_info.ccw.devno, loadparm);
+               get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM);
                __cpcmd(buf, NULL, 0, NULL);
                break;
        case REIPL_METHOD_CCW_DIAG:
@@ -691,8 +946,12 @@ static void reipl_run(struct shutdown_trigger *trigger)
        case REIPL_METHOD_FCP_RO_VM:
                __cpcmd("IPL", NULL, 0, NULL);
                break;
+       case REIPL_METHOD_NSS_DIAG:
+               diag308(DIAG308_SET, reipl_block_nss);
+               diag308(DIAG308_IPL, NULL);
+               break;
        case REIPL_METHOD_NSS:
-               sprintf(buf, "IPL %s", reipl_nss_name);
+               get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS);
                __cpcmd(buf, NULL, 0, NULL);
                break;
        case REIPL_METHOD_DEFAULT:
@@ -707,16 +966,36 @@ static void reipl_run(struct shutdown_trigger *trigger)
        disabled_wait((unsigned long) __builtin_return_address(0));
 }
 
-static void __init reipl_probe(void)
+static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
 {
-       void *buffer;
+       ipb->hdr.len = IPL_PARM_BLK_CCW_LEN;
+       ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
+       ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
+       ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW;
+}
 
-       buffer = (void *) get_zeroed_page(GFP_KERNEL);
-       if (!buffer)
-               return;
-       if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
-               diag308_set_works = 1;
-       free_page((unsigned long)buffer);
+static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
+{
+       /* LOADPARM */
+       /* check if read scp info worked and set loadparm */
+       if (sclp_ipl_info.is_valid)
+               memcpy(ipb->ipl_info.ccw.load_parm,
+                               &sclp_ipl_info.loadparm, LOADPARM_LEN);
+       else
+               /* read scp info failed: set empty loadparm (EBCDIC blanks) */
+               memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN);
+       ipb->hdr.flags = DIAG308_FLAGS_LP_VALID;
+
+       /* VM PARM */
+       if (MACHINE_IS_VM && diag308_set_works &&
+           (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) {
+
+               ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID;
+               ipb->ipl_info.ccw.vm_parm_len =
+                                       ipl_block.ipl_info.ccw.vm_parm_len;
+               memcpy(ipb->ipl_info.ccw.vm_parm,
+                      ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE);
+       }
 }
 
 static int __init reipl_nss_init(void)
@@ -725,10 +1004,31 @@ static int __init reipl_nss_init(void)
 
        if (!MACHINE_IS_VM)
                return 0;
+
+       reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!reipl_block_nss)
+               return -ENOMEM;
+
+       if (!diag308_set_works)
+               sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO;
+
        rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
        if (rc)
                return rc;
-       strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+
+       reipl_block_ccw_init(reipl_block_nss);
+       if (ipl_info.type == IPL_TYPE_NSS) {
+               memset(reipl_block_nss->ipl_info.ccw.nss_name,
+                       ' ', NSS_NAME_SIZE);
+               memcpy(reipl_block_nss->ipl_info.ccw.nss_name,
+                       kernel_nss_name, strlen(kernel_nss_name));
+               ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE);
+               reipl_block_nss->ipl_info.ccw.vm_flags |=
+                       DIAG308_VM_FLAGS_NSS_VALID;
+
+               reipl_block_ccw_fill_parms(reipl_block_nss);
+       }
+
        reipl_capabilities |= IPL_TYPE_NSS;
        return 0;
 }
@@ -740,28 +1040,27 @@ static int __init reipl_ccw_init(void)
        reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
        if (!reipl_block_ccw)
                return -ENOMEM;
-       rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
-       if (rc) {
-               free_page((unsigned long)reipl_block_ccw);
-               return rc;
+
+       if (MACHINE_IS_VM) {
+               if (!diag308_set_works)
+                       sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO;
+               rc = sysfs_create_group(&reipl_kset->kobj,
+                                       &reipl_ccw_attr_group_vm);
+       } else {
+               if(!diag308_set_works)
+                       sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
+               rc = sysfs_create_group(&reipl_kset->kobj,
+                                       &reipl_ccw_attr_group_lpar);
        }
-       reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
-       reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
-       reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
-       reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
-       reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
-       /* check if read scp info worked and set loadparm */
-       if (sclp_ipl_info.is_valid)
-               memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
-                      &sclp_ipl_info.loadparm, LOADPARM_LEN);
-       else
-               /* read scp info failed: set empty loadparm (EBCDIC blanks) */
-               memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
-                      LOADPARM_LEN);
-       if (!MACHINE_IS_VM && !diag308_set_works)
-               sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
-       if (ipl_info.type == IPL_TYPE_CCW)
+       if (rc)
+               return rc;
+
+       reipl_block_ccw_init(reipl_block_ccw);
+       if (ipl_info.type == IPL_TYPE_CCW) {
                reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
+               reipl_block_ccw_fill_parms(reipl_block_ccw);
+       }
+
        reipl_capabilities |= IPL_TYPE_CCW;
        return 0;
 }
@@ -1298,7 +1597,6 @@ static void __init shutdown_actions_init(void)
 
 static int __init s390_ipl_init(void)
 {
-       reipl_probe();
        sclp_get_ipl_info(&sclp_ipl_info);
        shutdown_actions_init();
        shutdown_triggers_init();
@@ -1405,6 +1703,12 @@ void __init setup_ipl(void)
        atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
 }
 
+void __init ipl_update_parameters(void)
+{
+       if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK)
+               diag308_set_works = 1;
+}
+
 void __init ipl_save_parameters(void)
 {
        struct cio_iplinfo iplinfo;
index ed04d1372d5d0c536b4a24713bf10d041bc79458..288ad490a6dd7ce931c0622c353d078eaf7a9799 100644 (file)
@@ -41,10 +41,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        if (is_prohibited_opcode((kprobe_opcode_t *) p->addr))
                return -EINVAL;
 
-       if ((unsigned long)p->addr & 0x01) {
-               printk("Attempt to register kprobe at an unaligned address\n");
+       if ((unsigned long)p->addr & 0x01)
                return -EINVAL;
-               }
 
        /* Use the get_insn_slot() facility for correctness */
        if (!(p->ainsn.insn = get_insn_slot()))
index 3c77dd36994cec6b71544a345a670d56353017d5..131d7ee8b416d8f6f8bb7f053c3799a3803e97ef 100644 (file)
@@ -52,7 +52,6 @@ void machine_kexec_cleanup(struct kimage *image)
 
 void machine_shutdown(void)
 {
-       printk(KERN_INFO "kexec: machine_shutdown called\n");
 }
 
 void machine_kexec(struct kimage *image)
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c
new file mode 100644 (file)
index 0000000..18ed7ab
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *    Copyright IBM Corp. 2008
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/ipl.h>
+#include <asm/sclp.h>
+#include <asm/setup.h>
+
+static int memory_fast_detect(struct mem_chunk *chunk)
+{
+       unsigned long val0 = 0;
+       unsigned long val1 = 0xc;
+       int rc = -EOPNOTSUPP;
+
+       if (ipl_flags & IPL_NSS_VALID)
+               return -EOPNOTSUPP;
+       asm volatile(
+               "       diag    %1,%2,0x260\n"
+               "0:     lhi     %0,0\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc), "+d" (val0), "+d" (val1) : : "cc");
+
+       if (rc || val0 != val1)
+               return -EOPNOTSUPP;
+       chunk->size = val0 + 1;
+       return 0;
+}
+
+static inline int tprot(unsigned long addr)
+{
+       int rc = -EFAULT;
+
+       asm volatile(
+               "       tprot   0(%1),0\n"
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) : "a" (addr) : "cc");
+       return rc;
+}
+
+#define ADDR2G (1ULL << 31)
+
+static void find_memory_chunks(struct mem_chunk chunk[])
+{
+       unsigned long long memsize, rnmax, rzm;
+       unsigned long addr = 0, size;
+       int i = 0, type;
+
+       rzm = sclp_get_rzm();
+       rnmax = sclp_get_rnmax();
+       memsize = rzm * rnmax;
+       if (!rzm)
+               rzm = 1ULL << 17;
+       if (sizeof(long) == 4) {
+               rzm = min(ADDR2G, rzm);
+               memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
+       }
+       do {
+               size = 0;
+               type = tprot(addr);
+               do {
+                       size += rzm;
+                       if (memsize && addr + size >= memsize)
+                               break;
+               } while (type == tprot(addr + size));
+               if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
+                       chunk[i].addr = addr;
+                       chunk[i].size = size;
+                       chunk[i].type = type;
+                       i++;
+               }
+               addr += size;
+       } while (addr < memsize && i < MEMORY_CHUNKS);
+}
+
+void detect_memory_layout(struct mem_chunk chunk[])
+{
+       unsigned long flags, cr0;
+
+       memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
+       if (memory_fast_detect(&chunk[0]) == 0)
+               return;
+       /* Disable IRQs, DAT and low address protection so tprot does the
+        * right thing and we don't get scheduled away with low address
+        * protection disabled.
+        */
+       flags = __raw_local_irq_stnsm(0xf8);
+       __ctl_store(cr0, 0, 0);
+       __ctl_clear_bit(0, 28);
+       find_memory_chunks(chunk);
+       __ctl_load(cr0, 0, 0);
+       __raw_local_irq_ssm(flags);
+}
+EXPORT_SYMBOL(detect_memory_layout);
index 7920861109d2aa074de0ca9ae96f2c99d3c44b24..85defd01d2937c36ccd0a92b18932969dfb8520f 100644 (file)
@@ -75,46 +75,19 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
        return sf->gprs[8];
 }
 
-/*
- * Need to know about CPUs going idle?
- */
-static ATOMIC_NOTIFIER_HEAD(idle_chain);
 DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
 
-int register_idle_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&idle_chain, nb);
-}
-EXPORT_SYMBOL(register_idle_notifier);
-
-int unregister_idle_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&idle_chain, nb);
-}
-EXPORT_SYMBOL(unregister_idle_notifier);
-
 static int s390_idle_enter(void)
 {
        struct s390_idle_data *idle;
-       int nr_calls = 0;
-       void *hcpu;
-       int rc;
 
-       hcpu = (void *)(long)smp_processor_id();
-       rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1,
-                                         &nr_calls);
-       if (rc == NOTIFY_BAD) {
-               nr_calls--;
-               __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE,
-                                            hcpu, nr_calls, NULL);
-               return rc;
-       }
        idle = &__get_cpu_var(s390_idle);
        spin_lock(&idle->lock);
        idle->idle_count++;
        idle->in_idle = 1;
        idle->idle_enter = get_clock();
        spin_unlock(&idle->lock);
+       vtime_stop_cpu_timer();
        return NOTIFY_OK;
 }
 
@@ -122,13 +95,12 @@ void s390_idle_leave(void)
 {
        struct s390_idle_data *idle;
 
+       vtime_start_cpu_timer();
        idle = &__get_cpu_var(s390_idle);
        spin_lock(&idle->lock);
        idle->idle_time += get_clock() - idle->idle_enter;
        idle->in_idle = 0;
        spin_unlock(&idle->lock);
-       atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE,
-                                  (void *)(long) smp_processor_id());
 }
 
 extern void s390_handle_mcck(void);
index 35827b9bd4d1827f102f79f3e999bbb69c52f5ab..2815bfe348a6f92e67b64e04e0b70cbecde6bc58 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/security.h>
 #include <linux/audit.h>
 #include <linux/signal.h>
+#include <linux/elf.h>
+#include <linux/regset.h>
 
 #include <asm/segment.h>
 #include <asm/page.h>
 #include "compat_ptrace.h"
 #endif
 
+enum s390_regset {
+       REGSET_GENERAL,
+       REGSET_FP,
+};
+
 static void
 FixPerRegisters(struct task_struct *task)
 {
@@ -126,24 +133,10 @@ ptrace_disable(struct task_struct *child)
  * struct user contain pad bytes that should be read as zeroes.
  * Lovely...
  */
-static int
-peek_user(struct task_struct *child, addr_t addr, addr_t data)
+static unsigned long __peek_user(struct task_struct *child, addr_t addr)
 {
        struct user *dummy = NULL;
-       addr_t offset, tmp, mask;
-
-       /*
-        * Stupid gdb peeks/pokes the access registers in 64 bit with
-        * an alignment of 4. Programmers from hell...
-        */
-       mask = __ADDR_MASK;
-#ifdef CONFIG_64BIT
-       if (addr >= (addr_t) &dummy->regs.acrs &&
-           addr < (addr_t) &dummy->regs.orig_gpr2)
-               mask = 3;
-#endif
-       if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
-               return -EIO;
+       addr_t offset, tmp;
 
        if (addr < (addr_t) &dummy->regs.acrs) {
                /*
@@ -197,24 +190,18 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
        } else
                tmp = 0;
 
-       return put_user(tmp, (addr_t __user *) data);
+       return tmp;
 }
 
-/*
- * Write a word to the user area of a process at location addr. This
- * operation does have an additional problem compared to peek_user.
- * Stores to the program status word and on the floating point
- * control register needs to get checked for validity.
- */
 static int
-poke_user(struct task_struct *child, addr_t addr, addr_t data)
+peek_user(struct task_struct *child, addr_t addr, addr_t data)
 {
        struct user *dummy = NULL;
-       addr_t offset, mask;
+       addr_t tmp, mask;
 
        /*
         * Stupid gdb peeks/pokes the access registers in 64 bit with
-        * an alignment of 4. Programmers from hell indeed...
+        * an alignment of 4. Programmers from hell...
         */
        mask = __ADDR_MASK;
 #ifdef CONFIG_64BIT
@@ -225,6 +212,21 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
        if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
                return -EIO;
 
+       tmp = __peek_user(child, addr);
+       return put_user(tmp, (addr_t __user *) data);
+}
+
+/*
+ * Write a word to the user area of a process at location addr. This
+ * operation does have an additional problem compared to peek_user.
+ * Stores to the program status word and on the floating point
+ * control register needs to get checked for validity.
+ */
+static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
+{
+       struct user *dummy = NULL;
+       addr_t offset;
+
        if (addr < (addr_t) &dummy->regs.acrs) {
                /*
                 * psw and gprs are stored on the stack
@@ -292,6 +294,28 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
        return 0;
 }
 
+static int
+poke_user(struct task_struct *child, addr_t addr, addr_t data)
+{
+       struct user *dummy = NULL;
+       addr_t mask;
+
+       /*
+        * Stupid gdb peeks/pokes the access registers in 64 bit with
+        * an alignment of 4. Programmers from hell indeed...
+        */
+       mask = __ADDR_MASK;
+#ifdef CONFIG_64BIT
+       if (addr >= (addr_t) &dummy->regs.acrs &&
+           addr < (addr_t) &dummy->regs.orig_gpr2)
+               mask = 3;
+#endif
+       if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
+               return -EIO;
+
+       return __poke_user(child, addr, data);
+}
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        ptrace_area parea; 
@@ -367,18 +391,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 /*
  * Same as peek_user but for a 31 bit program.
  */
-static int
-peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
+static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
 {
        struct user32 *dummy32 = NULL;
        per_struct32 *dummy_per32 = NULL;
        addr_t offset;
        __u32 tmp;
 
-       if (!test_thread_flag(TIF_31BIT) ||
-           (addr & 3) || addr > sizeof(struct user) - 3)
-               return -EIO;
-
        if (addr < (addr_t) &dummy32->regs.acrs) {
                /*
                 * psw and gprs are stored on the stack
@@ -435,25 +454,32 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
        } else
                tmp = 0;
 
+       return tmp;
+}
+
+static int peek_user_compat(struct task_struct *child,
+                           addr_t addr, addr_t data)
+{
+       __u32 tmp;
+
+       if (!test_thread_flag(TIF_31BIT) ||
+           (addr & 3) || addr > sizeof(struct user) - 3)
+               return -EIO;
+
+       tmp = __peek_user_compat(child, addr);
        return put_user(tmp, (__u32 __user *) data);
 }
 
 /*
  * Same as poke_user but for a 31 bit program.
  */
-static int
-poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
+static int __poke_user_compat(struct task_struct *child,
+                             addr_t addr, addr_t data)
 {
        struct user32 *dummy32 = NULL;
        per_struct32 *dummy_per32 = NULL;
+       __u32 tmp = (__u32) data;
        addr_t offset;
-       __u32 tmp;
-
-       if (!test_thread_flag(TIF_31BIT) ||
-           (addr & 3) || addr > sizeof(struct user32) - 3)
-               return -EIO;
-
-       tmp = (__u32) data;
 
        if (addr < (addr_t) &dummy32->regs.acrs) {
                /*
@@ -528,6 +554,16 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
        return 0;
 }
 
+static int poke_user_compat(struct task_struct *child,
+                           addr_t addr, addr_t data)
+{
+       if (!test_thread_flag(TIF_31BIT) ||
+           (addr & 3) || addr > sizeof(struct user32) - 3)
+               return -EIO;
+
+       return __poke_user_compat(child, addr, data);
+}
+
 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        compat_ulong_t caddr, compat_ulong_t cdata)
 {
@@ -539,11 +575,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
        switch (request) {
        case PTRACE_PEEKUSR:
                /* read the word at location addr in the USER area. */
-               return peek_user_emu31(child, addr, data);
+               return peek_user_compat(child, addr, data);
 
        case PTRACE_POKEUSR:
                /* write the word at location addr in the USER area */
-               return poke_user_emu31(child, addr, data);
+               return poke_user_compat(child, addr, data);
 
        case PTRACE_PEEKUSR_AREA:
        case PTRACE_POKEUSR_AREA:
@@ -555,13 +591,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                copied = 0;
                while (copied < parea.len) {
                        if (request == PTRACE_PEEKUSR_AREA)
-                               ret = peek_user_emu31(child, addr, data);
+                               ret = peek_user_compat(child, addr, data);
                        else {
                                __u32 utmp;
                                if (get_user(utmp,
                                             (__u32 __force __user *) data))
                                        return -EFAULT;
-                               ret = poke_user_emu31(child, addr, utmp);
+                               ret = poke_user_compat(child, addr, utmp);
                        }
                        if (ret)
                                return ret;
@@ -610,3 +646,240 @@ syscall_trace(struct pt_regs *regs, int entryexit)
                                    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
                                    regs->gprs[4], regs->gprs[5]);
 }
+
+/*
+ * user_regset definitions.
+ */
+
+static int s390_regs_get(struct task_struct *target,
+                        const struct user_regset *regset,
+                        unsigned int pos, unsigned int count,
+                        void *kbuf, void __user *ubuf)
+{
+       if (target == current)
+               save_access_regs(target->thread.acrs);
+
+       if (kbuf) {
+               unsigned long *k = kbuf;
+               while (count > 0) {
+                       *k++ = __peek_user(target, pos);
+                       count -= sizeof(*k);
+                       pos += sizeof(*k);
+               }
+       } else {
+               unsigned long __user *u = ubuf;
+               while (count > 0) {
+                       if (__put_user(__peek_user(target, pos), u++))
+                               return -EFAULT;
+                       count -= sizeof(*u);
+                       pos += sizeof(*u);
+               }
+       }
+       return 0;
+}
+
+static int s390_regs_set(struct task_struct *target,
+                        const struct user_regset *regset,
+                        unsigned int pos, unsigned int count,
+                        const void *kbuf, const void __user *ubuf)
+{
+       int rc = 0;
+
+       if (target == current)
+               save_access_regs(target->thread.acrs);
+
+       if (kbuf) {
+               const unsigned long *k = kbuf;
+               while (count > 0 && !rc) {
+                       rc = __poke_user(target, pos, *k++);
+                       count -= sizeof(*k);
+                       pos += sizeof(*k);
+               }
+       } else {
+               const unsigned long  __user *u = ubuf;
+               while (count > 0 && !rc) {
+                       unsigned long word;
+                       rc = __get_user(word, u++);
+                       if (rc)
+                               break;
+                       rc = __poke_user(target, pos, word);
+                       count -= sizeof(*u);
+                       pos += sizeof(*u);
+               }
+       }
+
+       if (rc == 0 && target == current)
+               restore_access_regs(target->thread.acrs);
+
+       return rc;
+}
+
+static int s390_fpregs_get(struct task_struct *target,
+                          const struct user_regset *regset, unsigned int pos,
+                          unsigned int count, void *kbuf, void __user *ubuf)
+{
+       if (target == current)
+               save_fp_regs(&target->thread.fp_regs);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  &target->thread.fp_regs, 0, -1);
+}
+
+static int s390_fpregs_set(struct task_struct *target,
+                          const struct user_regset *regset, unsigned int pos,
+                          unsigned int count, const void *kbuf,
+                          const void __user *ubuf)
+{
+       int rc = 0;
+
+       if (target == current)
+               save_fp_regs(&target->thread.fp_regs);
+
+       /* If setting FPC, must validate it first. */
+       if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
+               u32 fpc[2] = { target->thread.fp_regs.fpc, 0 };
+               rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc,
+                                       0, offsetof(s390_fp_regs, fprs));
+               if (rc)
+                       return rc;
+               if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0)
+                       return -EINVAL;
+               target->thread.fp_regs.fpc = fpc[0];
+       }
+
+       if (rc == 0 && count > 0)
+               rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                       target->thread.fp_regs.fprs,
+                                       offsetof(s390_fp_regs, fprs), -1);
+
+       if (rc == 0 && target == current)
+               restore_fp_regs(&target->thread.fp_regs);
+
+       return rc;
+}
+
+static const struct user_regset s390_regsets[] = {
+       [REGSET_GENERAL] = {
+               .core_note_type = NT_PRSTATUS,
+               .n = sizeof(s390_regs) / sizeof(long),
+               .size = sizeof(long),
+               .align = sizeof(long),
+               .get = s390_regs_get,
+               .set = s390_regs_set,
+       },
+       [REGSET_FP] = {
+               .core_note_type = NT_PRFPREG,
+               .n = sizeof(s390_fp_regs) / sizeof(long),
+               .size = sizeof(long),
+               .align = sizeof(long),
+               .get = s390_fpregs_get,
+               .set = s390_fpregs_set,
+       },
+};
+
+static const struct user_regset_view user_s390_view = {
+       .name = UTS_MACHINE,
+       .e_machine = EM_S390,
+       .regsets = s390_regsets,
+       .n = ARRAY_SIZE(s390_regsets)
+};
+
+#ifdef CONFIG_COMPAT
+static int s390_compat_regs_get(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               void *kbuf, void __user *ubuf)
+{
+       if (target == current)
+               save_access_regs(target->thread.acrs);
+
+       if (kbuf) {
+               compat_ulong_t *k = kbuf;
+               while (count > 0) {
+                       *k++ = __peek_user_compat(target, pos);
+                       count -= sizeof(*k);
+                       pos += sizeof(*k);
+               }
+       } else {
+               compat_ulong_t __user *u = ubuf;
+               while (count > 0) {
+                       if (__put_user(__peek_user_compat(target, pos), u++))
+                               return -EFAULT;
+                       count -= sizeof(*u);
+                       pos += sizeof(*u);
+               }
+       }
+       return 0;
+}
+
+static int s390_compat_regs_set(struct task_struct *target,
+                               const struct user_regset *regset,
+                               unsigned int pos, unsigned int count,
+                               const void *kbuf, const void __user *ubuf)
+{
+       int rc = 0;
+
+       if (target == current)
+               save_access_regs(target->thread.acrs);
+
+       if (kbuf) {
+               const compat_ulong_t *k = kbuf;
+               while (count > 0 && !rc) {
+                       rc = __poke_user_compat(target, pos, *k++);
+                       count -= sizeof(*k);
+                       pos += sizeof(*k);
+               }
+       } else {
+               const compat_ulong_t  __user *u = ubuf;
+               while (count > 0 && !rc) {
+                       compat_ulong_t word;
+                       rc = __get_user(word, u++);
+                       if (rc)
+                               break;
+                       rc = __poke_user_compat(target, pos, word);
+                       count -= sizeof(*u);
+                       pos += sizeof(*u);
+               }
+       }
+
+       if (rc == 0 && target == current)
+               restore_access_regs(target->thread.acrs);
+
+       return rc;
+}
+
+static const struct user_regset s390_compat_regsets[] = {
+       [REGSET_GENERAL] = {
+               .core_note_type = NT_PRSTATUS,
+               .n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
+               .size = sizeof(compat_long_t),
+               .align = sizeof(compat_long_t),
+               .get = s390_compat_regs_get,
+               .set = s390_compat_regs_set,
+       },
+       [REGSET_FP] = {
+               .core_note_type = NT_PRFPREG,
+               .n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
+               .size = sizeof(compat_long_t),
+               .align = sizeof(compat_long_t),
+               .get = s390_fpregs_get,
+               .set = s390_fpregs_set,
+       },
+};
+
+static const struct user_regset_view user_s390_compat_view = {
+       .name = "s390",
+       .e_machine = EM_S390,
+       .regsets = s390_compat_regsets,
+       .n = ARRAY_SIZE(s390_compat_regsets)
+};
+#endif
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+#ifdef CONFIG_COMPAT
+       if (test_tsk_thread_flag(task, TIF_31BIT))
+               return &user_s390_compat_view;
+#endif
+       return &user_s390_view;
+}
index 2bc70b6e876a4310991e884d5a1f92dde1a78681..b358e18273b07f2e1e31315e77835fd84f880bfc 100644 (file)
@@ -77,7 +77,7 @@ unsigned long machine_flags;
 unsigned long elf_hwcap = 0;
 char elf_platform[ELF_PLATFORM_SIZE];
 
-struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS];
+struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 static unsigned long __initdata memory_end;
 
@@ -205,12 +205,6 @@ static void __init conmode_default(void)
                        SET_CONSOLE_SCLP;
 #endif
                }
-        } else if (MACHINE_IS_P390) {
-#if defined(CONFIG_TN3215_CONSOLE)
-               SET_CONSOLE_3215;
-#elif defined(CONFIG_TN3270_CONSOLE)
-               SET_CONSOLE_3270;
-#endif
        } else {
 #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
                SET_CONSOLE_SCLP;
@@ -221,18 +215,17 @@ static void __init conmode_default(void)
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
 static void __init setup_zfcpdump(unsigned int console_devno)
 {
-       static char str[64];
+       static char str[41];
 
        if (ipl_info.type != IPL_TYPE_FCP_DUMP)
                return;
        if (console_devno != -1)
-               sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x",
+               sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x",
                        ipl_info.data.fcp.dev_id.devno, console_devno);
        else
-               sprintf(str, "cio_ignore=all,!0.0.%04x",
+               sprintf(str, " cio_ignore=all,!0.0.%04x",
                        ipl_info.data.fcp.dev_id.devno);
-       strcat(COMMAND_LINE, " ");
-       strcat(COMMAND_LINE, str);
+       strcat(boot_command_line, str);
        console_loglevel = 2;
 }
 #else
@@ -289,32 +282,6 @@ static int __init early_parse_mem(char *p)
 }
 early_param("mem", early_parse_mem);
 
-/*
- * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
- */
-static int __init early_parse_ipldelay(char *p)
-{
-       unsigned long delay = 0;
-
-       delay = simple_strtoul(p, &p, 0);
-
-       switch (*p) {
-       case 's':
-       case 'S':
-               delay *= 1000000;
-               break;
-       case 'm':
-       case 'M':
-               delay *= 60 * 1000000;
-       }
-
-       /* now wait for the requested amount of time */
-       udelay(delay);
-
-       return 0;
-}
-early_param("ipldelay", early_parse_ipldelay);
-
 #ifdef CONFIG_S390_SWITCH_AMODE
 #ifdef CONFIG_PGSTE
 unsigned int switch_amode = 1;
@@ -804,11 +771,9 @@ setup_arch(char **cmdline_p)
                printk("We are running native (64 bit mode)\n");
 #endif /* CONFIG_64BIT */
 
-       /* Save unparsed command line copy for /proc/cmdline */
-       strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
-
-       *cmdline_p = COMMAND_LINE;
-       *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0';
+       /* Have one command line that is parsed and saved in /proc/cmdline */
+       /* boot_command_line has been already set up in early.c */
+       *cmdline_p = boot_command_line;
 
         ROOT_DEV = Root_RAM0;
 
index 7aec676fefd593fcc7305613a6d1e3e4964cdbb0..7418bebb547fad641cb79a8b209e8d12d8b842c7 100644 (file)
@@ -3,7 +3,7 @@
  *    Time of day based timer functions.
  *
  *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 1999, 2008
  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
@@ -31,6 +31,7 @@
 #include <linux/notifier.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/bootmem.h>
 #include <asm/uaccess.h>
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
@@ -162,7 +163,7 @@ void init_cpu_timer(void)
        /* Enable clock comparator timer interrupt. */
        __ctl_set_bit(0,11);
 
-       /* Always allow ETR external interrupts, even without an ETR. */
+       /* Always allow the timing alert external interrupt. */
        __ctl_set_bit(0, 4);
 }
 
@@ -170,8 +171,21 @@ static void clock_comparator_interrupt(__u16 code)
 {
 }
 
+static void etr_timing_alert(struct etr_irq_parm *);
+static void stp_timing_alert(struct stp_irq_parm *);
+
+static void timing_alert_interrupt(__u16 code)
+{
+       if (S390_lowcore.ext_params & 0x00c40000)
+               etr_timing_alert((struct etr_irq_parm *)
+                                &S390_lowcore.ext_params);
+       if (S390_lowcore.ext_params & 0x00038000)
+               stp_timing_alert((struct stp_irq_parm *)
+                                &S390_lowcore.ext_params);
+}
+
 static void etr_reset(void);
-static void etr_ext_handler(__u16);
+static void stp_reset(void);
 
 /*
  * Get the TOD clock running.
@@ -181,6 +195,7 @@ static u64 __init reset_tod_clock(void)
        u64 time;
 
        etr_reset();
+       stp_reset();
        if (store_clock(&time) == 0)
                return time;
        /* TOD clock not running. Set the clock to Unix Epoch. */
@@ -231,8 +246,9 @@ void __init time_init(void)
        if (clocksource_register(&clocksource_tod) != 0)
                panic("Could not register TOD clock source");
 
-       /* request the etr external interrupt */
-       if (register_early_external_interrupt(0x1406, etr_ext_handler,
+       /* request the timing alert external interrupt */
+       if (register_early_external_interrupt(0x1406,
+                                             timing_alert_interrupt,
                                              &ext_int_etr_cc) != 0)
                panic("Couldn't request external interrupt 0x1406");
 
@@ -244,11 +260,113 @@ void __init time_init(void)
 #endif
 }
 
+/*
+ * The time is "clock". old is what we think the time is.
+ * Adjust the value by a multiple of jiffies and add the delta to ntp.
+ * "delay" is an approximation how long the synchronization took. If
+ * the time correction is positive, then "delay" is subtracted from
+ * the time difference and only the remaining part is passed to ntp.
+ */
+static unsigned long long adjust_time(unsigned long long old,
+                                     unsigned long long clock,
+                                     unsigned long long delay)
+{
+       unsigned long long delta, ticks;
+       struct timex adjust;
+
+       if (clock > old) {
+               /* It is later than we thought. */
+               delta = ticks = clock - old;
+               delta = ticks = (delta < delay) ? 0 : delta - delay;
+               delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+               adjust.offset = ticks * (1000000 / HZ);
+       } else {
+               /* It is earlier than we thought. */
+               delta = ticks = old - clock;
+               delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+               delta = -delta;
+               adjust.offset = -ticks * (1000000 / HZ);
+       }
+       jiffies_timer_cc += delta;
+       if (adjust.offset != 0) {
+               printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
+                      adjust.offset);
+               adjust.modes = ADJ_OFFSET_SINGLESHOT;
+               do_adjtimex(&adjust);
+       }
+       return delta;
+}
+
+static DEFINE_PER_CPU(atomic_t, clock_sync_word);
+static unsigned long clock_sync_flags;
+
+#define CLOCK_SYNC_HAS_ETR     0
+#define CLOCK_SYNC_HAS_STP     1
+#define CLOCK_SYNC_ETR         2
+#define CLOCK_SYNC_STP         3
+
+/*
+ * The synchronous get_clock function. It will write the current clock
+ * value to the clock pointer and return 0 if the clock is in sync with
+ * the external time source. If the clock mode is local it will return
+ * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * reference.
+ */
+int get_sync_clock(unsigned long long *clock)
+{
+       atomic_t *sw_ptr;
+       unsigned int sw0, sw1;
+
+       sw_ptr = &get_cpu_var(clock_sync_word);
+       sw0 = atomic_read(sw_ptr);
+       *clock = get_clock();
+       sw1 = atomic_read(sw_ptr);
+       put_cpu_var(clock_sync_sync);
+       if (sw0 == sw1 && (sw0 & 0x80000000U))
+               /* Success: time is in sync. */
+               return 0;
+       if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) &&
+           !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags))
+               return -ENOSYS;
+       if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) &&
+           !test_bit(CLOCK_SYNC_STP, &clock_sync_flags))
+               return -EACCES;
+       return -EAGAIN;
+}
+EXPORT_SYMBOL(get_sync_clock);
+
+/*
+ * Make get_sync_clock return -EAGAIN.
+ */
+static void disable_sync_clock(void *dummy)
+{
+       atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word);
+       /*
+        * Clear the in-sync bit 2^31. All get_sync_clock calls will
+        * fail until the sync bit is turned back on. In addition
+        * increase the "sequence" counter to avoid the race of an
+        * etr event and the complete recovery against get_sync_clock.
+        */
+       atomic_clear_mask(0x80000000, sw_ptr);
+       atomic_inc(sw_ptr);
+}
+
+/*
+ * Make get_sync_clock return 0 again.
+ * Needs to be called from a context disabled for preemption.
+ */
+static void enable_sync_clock(void)
+{
+       atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word);
+       atomic_set_mask(0x80000000, sw_ptr);
+}
+
 /*
  * External Time Reference (ETR) code.
  */
 static int etr_port0_online;
 static int etr_port1_online;
+static int etr_steai_available;
 
 static int __init early_parse_etr(char *p)
 {
@@ -273,12 +391,6 @@ enum etr_event {
        ETR_EVENT_UPDATE,
 };
 
-enum etr_flags {
-       ETR_FLAG_ENOSYS,
-       ETR_FLAG_EACCES,
-       ETR_FLAG_STEAI,
-};
-
 /*
  * Valid bit combinations of the eacr register are (x = don't care):
  * e0 e1 dp p0 p1 ea es sl
@@ -305,73 +417,17 @@ enum etr_flags {
  */
 static struct etr_eacr etr_eacr;
 static u64 etr_tolec;                  /* time of last eacr update */
-static unsigned long etr_flags;
 static struct etr_aib etr_port0;
 static int etr_port0_uptodate;
 static struct etr_aib etr_port1;
 static int etr_port1_uptodate;
 static unsigned long etr_events;
 static struct timer_list etr_timer;
-static DEFINE_PER_CPU(atomic_t, etr_sync_word);
 
 static void etr_timeout(unsigned long dummy);
 static void etr_work_fn(struct work_struct *work);
 static DECLARE_WORK(etr_work, etr_work_fn);
 
-/*
- * The etr get_clock function. It will write the current clock value
- * to the clock pointer and return 0 if the clock is in sync with the
- * external time source. If the clock mode is local it will return
- * -ENOSYS and -EAGAIN if the clock is not in sync with the external
- * reference. This function is what ETR is all about..
- */
-int get_sync_clock(unsigned long long *clock)
-{
-       atomic_t *sw_ptr;
-       unsigned int sw0, sw1;
-
-       sw_ptr = &get_cpu_var(etr_sync_word);
-       sw0 = atomic_read(sw_ptr);
-       *clock = get_clock();
-       sw1 = atomic_read(sw_ptr);
-       put_cpu_var(etr_sync_sync);
-       if (sw0 == sw1 && (sw0 & 0x80000000U))
-               /* Success: time is in sync. */
-               return 0;
-       if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
-               return -ENOSYS;
-       if (test_bit(ETR_FLAG_EACCES, &etr_flags))
-               return -EACCES;
-       return -EAGAIN;
-}
-EXPORT_SYMBOL(get_sync_clock);
-
-/*
- * Make get_sync_clock return -EAGAIN.
- */
-static void etr_disable_sync_clock(void *dummy)
-{
-       atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
-       /*
-        * Clear the in-sync bit 2^31. All get_sync_clock calls will
-        * fail until the sync bit is turned back on. In addition
-        * increase the "sequence" counter to avoid the race of an
-        * etr event and the complete recovery against get_sync_clock.
-        */
-       atomic_clear_mask(0x80000000, sw_ptr);
-       atomic_inc(sw_ptr);
-}
-
-/*
- * Make get_sync_clock return 0 again.
- * Needs to be called from a context disabled for preemption.
- */
-static void etr_enable_sync_clock(void)
-{
-       atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
-       atomic_set_mask(0x80000000, sw_ptr);
-}
-
 /*
  * Reset ETR attachment.
  */
@@ -381,15 +437,13 @@ static void etr_reset(void)
                .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0,
                .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
                .es = 0, .sl = 0 };
-       if (etr_setr(&etr_eacr) == 0)
+       if (etr_setr(&etr_eacr) == 0) {
                etr_tolec = get_clock();
-       else {
-               set_bit(ETR_FLAG_ENOSYS, &etr_flags);
-               if (etr_port0_online || etr_port1_online) {
-                       printk(KERN_WARNING "Running on non ETR capable "
-                              "machine, only local mode available.\n");
-                       etr_port0_online = etr_port1_online = 0;
-               }
+               set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags);
+       } else if (etr_port0_online || etr_port1_online) {
+               printk(KERN_WARNING "Running on non ETR capable "
+                      "machine, only local mode available.\n");
+               etr_port0_online = etr_port1_online = 0;
        }
 }
 
@@ -397,14 +451,12 @@ static int __init etr_init(void)
 {
        struct etr_aib aib;
 
-       if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+       if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags))
                return 0;
        /* Check if this machine has the steai instruction. */
        if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
-               set_bit(ETR_FLAG_STEAI, &etr_flags);
+               etr_steai_available = 1;
        setup_timer(&etr_timer, etr_timeout, 0UL);
-       if (!etr_port0_online && !etr_port1_online)
-               set_bit(ETR_FLAG_EACCES, &etr_flags);
        if (etr_port0_online) {
                set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
                schedule_work(&etr_work);
@@ -435,7 +487,8 @@ void etr_switch_to_local(void)
 {
        if (!etr_eacr.sl)
                return;
-       etr_disable_sync_clock(NULL);
+       if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
+               disable_sync_clock(NULL);
        set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
        schedule_work(&etr_work);
 }
@@ -450,23 +503,21 @@ void etr_sync_check(void)
 {
        if (!etr_eacr.es)
                return;
-       etr_disable_sync_clock(NULL);
+       if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
+               disable_sync_clock(NULL);
        set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
        schedule_work(&etr_work);
 }
 
 /*
- * ETR external interrupt. There are two causes:
+ * ETR timing alert. There are two causes:
  * 1) port state change, check the usability of the port
  * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the
  *    sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3)
  *    or ETR-data word 4 (edf4) has changed.
  */
-static void etr_ext_handler(__u16 code)
+static void etr_timing_alert(struct etr_irq_parm *intparm)
 {
-       struct etr_interruption_parameter *intparm =
-               (struct etr_interruption_parameter *) &S390_lowcore.ext_params;
-
        if (intparm->pc0)
                /* ETR port 0 state change. */
                set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
@@ -591,58 +642,23 @@ static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
        return 1;
 }
 
-/*
- * The time is "clock". old is what we think the time is.
- * Adjust the value by a multiple of jiffies and add the delta to ntp.
- * "delay" is an approximation how long the synchronization took. If
- * the time correction is positive, then "delay" is subtracted from
- * the time difference and only the remaining part is passed to ntp.
- */
-static unsigned long long etr_adjust_time(unsigned long long old,
-                                         unsigned long long clock,
-                                         unsigned long long delay)
-{
-       unsigned long long delta, ticks;
-       struct timex adjust;
-
-       if (clock > old) {
-               /* It is later than we thought. */
-               delta = ticks = clock - old;
-               delta = ticks = (delta < delay) ? 0 : delta - delay;
-               delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
-               adjust.offset = ticks * (1000000 / HZ);
-       } else {
-               /* It is earlier than we thought. */
-               delta = ticks = old - clock;
-               delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
-               delta = -delta;
-               adjust.offset = -ticks * (1000000 / HZ);
-       }
-       jiffies_timer_cc += delta;
-       if (adjust.offset != 0) {
-               printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
-                      adjust.offset);
-               adjust.modes = ADJ_OFFSET_SINGLESHOT;
-               do_adjtimex(&adjust);
-       }
-       return delta;
-}
-
-static struct {
+struct clock_sync_data {
        int in_sync;
        unsigned long long fixup_cc;
-} etr_sync;
+};
 
-static void etr_sync_cpu_start(void *dummy)
+static void clock_sync_cpu_start(void *dummy)
 {
-       etr_enable_sync_clock();
+       struct clock_sync_data *sync = dummy;
+
+       enable_sync_clock();
        /*
         * This looks like a busy wait loop but it isn't. etr_sync_cpus
         * is called on all other cpus while the TOD clocks is stopped.
         * __udelay will stop the cpu on an enabled wait psw until the
         * TOD is running again.
         */
-       while (etr_sync.in_sync == 0) {
+       while (sync->in_sync == 0) {
                __udelay(1);
                /*
                 * A different cpu changes *in_sync. Therefore use
@@ -650,17 +666,17 @@ static void etr_sync_cpu_start(void *dummy)
                 */
                barrier();
        }
-       if (etr_sync.in_sync != 1)
+       if (sync->in_sync != 1)
                /* Didn't work. Clear per-cpu in sync bit again. */
-               etr_disable_sync_clock(NULL);
+               disable_sync_clock(NULL);
        /*
         * This round of TOD syncing is done. Set the clock comparator
         * to the next tick and let the processor continue.
         */
-       fixup_clock_comparator(etr_sync.fixup_cc);
+       fixup_clock_comparator(sync->fixup_cc);
 }
 
-static void etr_sync_cpu_end(void *dummy)
+static void clock_sync_cpu_end(void *dummy)
 {
 }
 
@@ -672,6 +688,7 @@ static void etr_sync_cpu_end(void *dummy)
 static int etr_sync_clock(struct etr_aib *aib, int port)
 {
        struct etr_aib *sync_port;
+       struct clock_sync_data etr_sync;
        unsigned long long clock, old_clock, delay, delta;
        int follows;
        int rc;
@@ -690,9 +707,9 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
         */
        memset(&etr_sync, 0, sizeof(etr_sync));
        preempt_disable();
-       smp_call_function(etr_sync_cpu_start, NULL, 0, 0);
+       smp_call_function(clock_sync_cpu_start, &etr_sync, 0, 0);
        local_irq_disable();
-       etr_enable_sync_clock();
+       enable_sync_clock();
 
        /* Set clock to next OTE. */
        __ctl_set_bit(14, 21);
@@ -707,13 +724,13 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
                /* Adjust Linux timing variables. */
                delay = (unsigned long long)
                        (aib->edf2.etv - sync_port->edf2.etv) << 32;
-               delta = etr_adjust_time(old_clock, clock, delay);
+               delta = adjust_time(old_clock, clock, delay);
                etr_sync.fixup_cc = delta;
                fixup_clock_comparator(delta);
                /* Verify that the clock is properly set. */
                if (!etr_aib_follows(sync_port, aib, port)) {
                        /* Didn't work. */
-                       etr_disable_sync_clock(NULL);
+                       disable_sync_clock(NULL);
                        etr_sync.in_sync = -EAGAIN;
                        rc = -EAGAIN;
                } else {
@@ -724,12 +741,12 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
                /* Could not set the clock ?!? */
                __ctl_clear_bit(0, 29);
                __ctl_clear_bit(14, 21);
-               etr_disable_sync_clock(NULL);
+               disable_sync_clock(NULL);
                etr_sync.in_sync = -EAGAIN;
                rc = -EAGAIN;
        }
        local_irq_enable();
-       smp_call_function(etr_sync_cpu_end,NULL,0,0);
+       smp_call_function(clock_sync_cpu_end, NULL, 0, 0);
        preempt_enable();
        return rc;
 }
@@ -832,7 +849,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib,
         * Do not try to get the alternate port aib if the clock
         * is not in sync yet.
         */
-       if (!eacr.es)
+       if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags) && !eacr.es)
                return eacr;
 
        /*
@@ -840,7 +857,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib,
         * the other port immediately. If only stetr is available the
         * data-port bit toggle has to be used.
         */
-       if (test_bit(ETR_FLAG_STEAI, &etr_flags)) {
+       if (etr_steai_available) {
                if (eacr.p0 && !etr_port0_uptodate) {
                        etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0);
                        etr_port0_uptodate = 1;
@@ -909,10 +926,10 @@ static void etr_work_fn(struct work_struct *work)
        if (!eacr.ea) {
                /* Both ports offline. Reset everything. */
                eacr.dp = eacr.es = eacr.sl = 0;
-               on_each_cpu(etr_disable_sync_clock, NULL, 0, 1);
+               on_each_cpu(disable_sync_clock, NULL, 0, 1);
                del_timer_sync(&etr_timer);
                etr_update_eacr(eacr);
-               set_bit(ETR_FLAG_EACCES, &etr_flags);
+               clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
                return;
        }
 
@@ -953,7 +970,6 @@ static void etr_work_fn(struct work_struct *work)
                        eacr.e1 = 1;
                sync_port = (etr_port0_uptodate &&
                             etr_port_valid(&etr_port0, 0)) ? 0 : -1;
-               clear_bit(ETR_FLAG_EACCES, &etr_flags);
        } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) {
                eacr.sl = 0;
                eacr.e0 = 0;
@@ -962,7 +978,6 @@ static void etr_work_fn(struct work_struct *work)
                        eacr.es = 0;
                sync_port = (etr_port1_uptodate &&
                             etr_port_valid(&etr_port1, 1)) ? 1 : -1;
-               clear_bit(ETR_FLAG_EACCES, &etr_flags);
        } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) {
                eacr.sl = 1;
                eacr.e0 = 1;
@@ -976,7 +991,6 @@ static void etr_work_fn(struct work_struct *work)
                        eacr.e1 = 1;
                sync_port = (etr_port0_uptodate &&
                             etr_port_valid(&etr_port0, 0)) ? 0 : -1;
-               clear_bit(ETR_FLAG_EACCES, &etr_flags);
        } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) {
                eacr.sl = 1;
                eacr.e0 = 0;
@@ -985,19 +999,22 @@ static void etr_work_fn(struct work_struct *work)
                        eacr.es = 0;
                sync_port = (etr_port1_uptodate &&
                             etr_port_valid(&etr_port1, 1)) ? 1 : -1;
-               clear_bit(ETR_FLAG_EACCES, &etr_flags);
        } else {
                /* Both ports not usable. */
                eacr.es = eacr.sl = 0;
                sync_port = -1;
-               set_bit(ETR_FLAG_EACCES, &etr_flags);
+               clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
        }
 
+       if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
+               eacr.es = 0;
+
        /*
         * If the clock is in sync just update the eacr and return.
         * If there is no valid sync port wait for a port update.
         */
-       if (eacr.es || sync_port < 0) {
+       if (test_bit(CLOCK_SYNC_STP, &clock_sync_flags) ||
+           eacr.es || sync_port < 0) {
                etr_update_eacr(eacr);
                etr_set_tolec_timeout(now);
                return;
@@ -1018,11 +1035,13 @@ static void etr_work_fn(struct work_struct *work)
         * and set up a timer to try again after 0.5 seconds
         */
        etr_update_eacr(eacr);
+       set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
        if (now < etr_tolec + (1600000 << 12) ||
            etr_sync_clock(&aib, sync_port) != 0) {
                /* Sync failed. Try again in 1/2 second. */
                eacr.es = 0;
                etr_update_eacr(eacr);
+               clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
                etr_set_sync_timeout();
        } else
                etr_set_tolec_timeout(now);
@@ -1097,8 +1116,8 @@ static ssize_t etr_online_store(struct sys_device *dev,
        value = simple_strtoul(buf, NULL, 0);
        if (value != 0 && value != 1)
                return -EINVAL;
-       if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
-               return -ENOSYS;
+       if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags))
+               return -EOPNOTSUPP;
        if (dev == &etr_port0_dev) {
                if (etr_port0_online == value)
                        return count;   /* Nothing to do. */
@@ -1292,3 +1311,318 @@ out:
 }
 
 device_initcall(etr_init_sysfs);
+
+/*
+ * Server Time Protocol (STP) code.
+ */
+static int stp_online;
+static struct stp_sstpi stp_info;
+static void *stp_page;
+
+static void stp_work_fn(struct work_struct *work);
+static DECLARE_WORK(stp_work, stp_work_fn);
+
+static int __init early_parse_stp(char *p)
+{
+       if (strncmp(p, "off", 3) == 0)
+               stp_online = 0;
+       else if (strncmp(p, "on", 2) == 0)
+               stp_online = 1;
+       return 0;
+}
+early_param("stp", early_parse_stp);
+
+/*
+ * Reset STP attachment.
+ */
+static void stp_reset(void)
+{
+       int rc;
+
+       stp_page = alloc_bootmem_pages(PAGE_SIZE);
+       rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
+       if (rc == 1)
+               set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
+       else if (stp_online) {
+               printk(KERN_WARNING "Running on non STP capable machine.\n");
+               free_bootmem((unsigned long) stp_page, PAGE_SIZE);
+               stp_page = NULL;
+               stp_online = 0;
+       }
+}
+
+static int __init stp_init(void)
+{
+       if (test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online)
+               schedule_work(&stp_work);
+       return 0;
+}
+
+arch_initcall(stp_init);
+
+/*
+ * STP timing alert. There are three causes:
+ * 1) timing status change
+ * 2) link availability change
+ * 3) time control parameter change
+ * In all three cases we are only interested in the clock source state.
+ * If a STP clock source is now available use it.
+ */
+static void stp_timing_alert(struct stp_irq_parm *intparm)
+{
+       if (intparm->tsc || intparm->lac || intparm->tcpc)
+               schedule_work(&stp_work);
+}
+
+/*
+ * STP sync check machine check. This is called when the timing state
+ * changes from the synchronized state to the unsynchronized state.
+ * After a STP sync check the clock is not in sync. The machine check
+ * is broadcasted to all cpus at the same time.
+ */
+void stp_sync_check(void)
+{
+       if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags))
+               return;
+       disable_sync_clock(NULL);
+       schedule_work(&stp_work);
+}
+
+/*
+ * STP island condition machine check. This is called when an attached
+ * server  attempts to communicate over an STP link and the servers
+ * have matching CTN ids and have a valid stratum-1 configuration
+ * but the configurations do not match.
+ */
+void stp_island_check(void)
+{
+       if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags))
+               return;
+       disable_sync_clock(NULL);
+       schedule_work(&stp_work);
+}
+
+/*
+ * STP tasklet. Check for the STP state and take over the clock
+ * synchronization if the STP clock source is usable.
+ */
+static void stp_work_fn(struct work_struct *work)
+{
+       struct clock_sync_data stp_sync;
+       unsigned long long old_clock, delta;
+       int rc;
+
+       if (!stp_online) {
+               chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
+               return;
+       }
+
+       rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0);
+       if (rc)
+               return;
+
+       rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
+       if (rc || stp_info.c == 0)
+               return;
+
+       /*
+        * Catch all other cpus and make them wait until we have
+        * successfully synced the clock. smp_call_function will
+        * return after all other cpus are in clock_sync_cpu_start.
+        */
+       memset(&stp_sync, 0, sizeof(stp_sync));
+       preempt_disable();
+       smp_call_function(clock_sync_cpu_start, &stp_sync, 0, 0);
+       local_irq_disable();
+       enable_sync_clock();
+
+       set_bit(CLOCK_SYNC_STP, &clock_sync_flags);
+       if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags))
+               schedule_work(&etr_work);
+
+       rc = 0;
+       if (stp_info.todoff[0] || stp_info.todoff[1] ||
+           stp_info.todoff[2] || stp_info.todoff[3] ||
+           stp_info.tmd != 2) {
+               old_clock = get_clock();
+               rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0);
+               if (rc == 0) {
+                       delta = adjust_time(old_clock, get_clock(), 0);
+                       fixup_clock_comparator(delta);
+                       rc = chsc_sstpi(stp_page, &stp_info,
+                                       sizeof(struct stp_sstpi));
+                       if (rc == 0 && stp_info.tmd != 2)
+                               rc = -EAGAIN;
+               }
+       }
+       if (rc) {
+               disable_sync_clock(NULL);
+               stp_sync.in_sync = -EAGAIN;
+               clear_bit(CLOCK_SYNC_STP, &clock_sync_flags);
+               if (etr_port0_online || etr_port1_online)
+                       schedule_work(&etr_work);
+       } else
+               stp_sync.in_sync = 1;
+
+       local_irq_enable();
+       smp_call_function(clock_sync_cpu_end, NULL, 0, 0);
+       preempt_enable();
+}
+
+/*
+ * STP class sysfs interface functions
+ */
+static struct sysdev_class stp_sysclass = {
+       .name   = "stp",
+};
+
+static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online)
+               return -ENODATA;
+       return sprintf(buf, "%016llx\n",
+                      *(unsigned long long *) stp_info.ctnid);
+}
+
+static SYSDEV_CLASS_ATTR(ctn_id, 0400, stp_ctn_id_show, NULL);
+
+static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", stp_info.ctn);
+}
+
+static SYSDEV_CLASS_ATTR(ctn_type, 0400, stp_ctn_type_show, NULL);
+
+static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online || !(stp_info.vbits & 0x2000))
+               return -ENODATA;
+       return sprintf(buf, "%i\n", (int)(s16) stp_info.dsto);
+}
+
+static SYSDEV_CLASS_ATTR(dst_offset, 0400, stp_dst_offset_show, NULL);
+
+static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online || !(stp_info.vbits & 0x8000))
+               return -ENODATA;
+       return sprintf(buf, "%i\n", (int)(s16) stp_info.leaps);
+}
+
+static SYSDEV_CLASS_ATTR(leap_seconds, 0400, stp_leap_seconds_show, NULL);
+
+static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", (int)(s16) stp_info.stratum);
+}
+
+static SYSDEV_CLASS_ATTR(stratum, 0400, stp_stratum_show, NULL);
+
+static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online || !(stp_info.vbits & 0x0800))
+               return -ENODATA;
+       return sprintf(buf, "%i\n", (int) stp_info.tto);
+}
+
+static SYSDEV_CLASS_ATTR(time_offset, 0400, stp_time_offset_show, NULL);
+
+static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online || !(stp_info.vbits & 0x4000))
+               return -ENODATA;
+       return sprintf(buf, "%i\n", (int)(s16) stp_info.tzo);
+}
+
+static SYSDEV_CLASS_ATTR(time_zone_offset, 0400,
+                        stp_time_zone_offset_show, NULL);
+
+static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", stp_info.tmd);
+}
+
+static SYSDEV_CLASS_ATTR(timing_mode, 0400, stp_timing_mode_show, NULL);
+
+static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf)
+{
+       if (!stp_online)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", stp_info.tst);
+}
+
+static SYSDEV_CLASS_ATTR(timing_state, 0400, stp_timing_state_show, NULL);
+
+static ssize_t stp_online_show(struct sysdev_class *class, char *buf)
+{
+       return sprintf(buf, "%i\n", stp_online);
+}
+
+static ssize_t stp_online_store(struct sysdev_class *class,
+                               const char *buf, size_t count)
+{
+       unsigned int value;
+
+       value = simple_strtoul(buf, NULL, 0);
+       if (value != 0 && value != 1)
+               return -EINVAL;
+       if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags))
+               return -EOPNOTSUPP;
+       stp_online = value;
+       schedule_work(&stp_work);
+       return count;
+}
+
+/*
+ * Can't use SYSDEV_CLASS_ATTR because the attribute should be named
+ * stp/online but attr_online already exists in this file ..
+ */
+static struct sysdev_class_attribute attr_stp_online = {
+       .attr = { .name = "online", .mode = 0600 },
+       .show   = stp_online_show,
+       .store  = stp_online_store,
+};
+
+static struct sysdev_class_attribute *stp_attributes[] = {
+       &attr_ctn_id,
+       &attr_ctn_type,
+       &attr_dst_offset,
+       &attr_leap_seconds,
+       &attr_stp_online,
+       &attr_stratum,
+       &attr_time_offset,
+       &attr_time_zone_offset,
+       &attr_timing_mode,
+       &attr_timing_state,
+       NULL
+};
+
+static int __init stp_init_sysfs(void)
+{
+       struct sysdev_class_attribute **attr;
+       int rc;
+
+       rc = sysdev_class_register(&stp_sysclass);
+       if (rc)
+               goto out;
+       for (attr = stp_attributes; *attr; attr++) {
+               rc = sysdev_class_create_file(&stp_sysclass, *attr);
+               if (rc)
+                       goto out_unreg;
+       }
+       return 0;
+out_unreg:
+       for (; attr >= stp_attributes; attr--)
+               sysdev_class_remove_file(&stp_sysclass, *attr);
+       sysdev_class_unregister(&stp_sysclass);
+out:
+       return rc;
+}
+
+device_initcall(stp_init_sysfs);
index 661a07217057a37b8d08b7ad85c8d4a2508a2bd0..212d618b00952a17152e9985b8a3d27a3ac657cd 100644 (file)
@@ -313,8 +313,6 @@ void __init s390_init_cpu_topology(void)
                machine_has_topology_irq = 1;
 
        tl_info = alloc_bootmem_pages(PAGE_SIZE);
-       if (!tl_info)
-               goto error;
        info = tl_info;
        stsi(info, 15, 1, 2);
 
index ca90ee3f930edc0ffc364d8a094826df731b3415..0fa5dc5d68e1dc2973459d60a71c491f59c6b631 100644 (file)
@@ -136,7 +136,7 @@ static inline void set_vtimer(__u64 expires)
 }
 #endif
 
-static void start_cpu_timer(void)
+void vtime_start_cpu_timer(void)
 {
        struct vtimer_queue *vt_list;
 
@@ -150,7 +150,7 @@ static void start_cpu_timer(void)
                set_vtimer(vt_list->idle);
 }
 
-static void stop_cpu_timer(void)
+void vtime_stop_cpu_timer(void)
 {
        struct vtimer_queue *vt_list;
 
@@ -318,8 +318,7 @@ static void internal_add_vtimer(struct vtimer_list *timer)
        vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
        spin_lock_irqsave(&vt_list->lock, flags);
 
-       if (timer->cpu != smp_processor_id())
-               printk("internal_add_vtimer: BUG, running on wrong CPU");
+       BUG_ON(timer->cpu != smp_processor_id());
 
        /* if list is empty we only have to set the timer */
        if (list_empty(&vt_list->list)) {
@@ -353,25 +352,12 @@ static void internal_add_vtimer(struct vtimer_list *timer)
        put_cpu();
 }
 
-static inline int prepare_vtimer(struct vtimer_list *timer)
+static inline void prepare_vtimer(struct vtimer_list *timer)
 {
-       if (!timer->function) {
-               printk("add_virt_timer: uninitialized timer\n");
-               return -EINVAL;
-       }
-
-       if (!timer->expires || timer->expires > VTIMER_MAX_SLICE) {
-               printk("add_virt_timer: invalid timer expire value!\n");
-               return -EINVAL;
-       }
-
-       if (vtimer_pending(timer)) {
-               printk("add_virt_timer: timer pending\n");
-               return -EBUSY;
-       }
-
+       BUG_ON(!timer->function);
+       BUG_ON(!timer->expires || timer->expires > VTIMER_MAX_SLICE);
+       BUG_ON(vtimer_pending(timer));
        timer->cpu = get_cpu();
-       return 0;
 }
 
 /*
@@ -382,10 +368,7 @@ void add_virt_timer(void *new)
        struct vtimer_list *timer;
 
        timer = (struct vtimer_list *)new;
-
-       if (prepare_vtimer(timer) < 0)
-               return;
-
+       prepare_vtimer(timer);
        timer->interval = 0;
        internal_add_vtimer(timer);
 }
@@ -399,10 +382,7 @@ void add_virt_timer_periodic(void *new)
        struct vtimer_list *timer;
 
        timer = (struct vtimer_list *)new;
-
-       if (prepare_vtimer(timer) < 0)
-               return;
-
+       prepare_vtimer(timer);
        timer->interval = timer->expires;
        internal_add_vtimer(timer);
 }
@@ -423,15 +403,8 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
        unsigned long flags;
        int cpu;
 
-       if (!timer->function) {
-               printk("mod_virt_timer: uninitialized timer\n");
-               return  -EINVAL;
-       }
-
-       if (!expires || expires > VTIMER_MAX_SLICE) {
-               printk("mod_virt_timer: invalid expire range\n");
-               return -EINVAL;
-       }
+       BUG_ON(!timer->function);
+       BUG_ON(!expires || expires > VTIMER_MAX_SLICE);
 
        /*
         * This is a common optimization triggered by the
@@ -444,6 +417,9 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
        cpu = get_cpu();
        vt_list = &per_cpu(virt_cpu_timer, cpu);
 
+       /* check if we run on the right CPU */
+       BUG_ON(timer->cpu != cpu);
+
        /* disable interrupts before test if timer is pending */
        spin_lock_irqsave(&vt_list->lock, flags);
 
@@ -458,14 +434,6 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
                return 0;
        }
 
-       /* check if we run on the right CPU */
-       if (timer->cpu != cpu) {
-               printk("mod_virt_timer: running on wrong CPU, check your code\n");
-               spin_unlock_irqrestore(&vt_list->lock, flags);
-               put_cpu();
-               return -EINVAL;
-       }
-
        list_del_init(&timer->entry);
        timer->expires = expires;
 
@@ -536,24 +504,6 @@ void init_cpu_vtimer(void)
 
 }
 
-static int vtimer_idle_notify(struct notifier_block *self,
-                             unsigned long action, void *hcpu)
-{
-       switch (action) {
-       case S390_CPU_IDLE:
-               stop_cpu_timer();
-               break;
-       case S390_CPU_NOT_IDLE:
-               start_cpu_timer();
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block vtimer_idle_nb = {
-       .notifier_call = vtimer_idle_notify,
-};
-
 void __init vtime_init(void)
 {
        /* request the cpu timer external interrupt */
@@ -561,9 +511,6 @@ void __init vtime_init(void)
                                              &ext_int_info_timer) != 0)
                panic("Couldn't request external interrupt 0x1005");
 
-       if (register_idle_notifier(&vtimer_idle_nb))
-               panic("Couldn't register idle notifier");
-
        /* Enable cpu timer interrupts on the boot cpu. */
        init_cpu_vtimer();
 }
index 05598649b3260f8689845ea2815914ffdd08e902..388cc742005544b05747d32a485e88c5c37cf5a6 100644 (file)
@@ -202,3 +202,22 @@ void free_initrd_mem(unsigned long start, unsigned long end)
         }
 }
 #endif
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+int arch_add_memory(int nid, u64 start, u64 size)
+{
+       struct pglist_data *pgdat;
+       struct zone *zone;
+       int rc;
+
+       pgdat = NODE_DATA(nid);
+       zone = pgdat->node_zones + ZONE_NORMAL;
+       rc = vmem_add_mapping(start, size);
+       if (rc)
+               return rc;
+       rc = __add_pages(zone, PFN_DOWN(start), PFN_DOWN(size));
+       if (rc)
+               vmem_remove_mapping(start, size);
+       return rc;
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
index bf07b6f50fa178268f9d81388a615a7a8abff32b..2cfccc987a2605e81f7017f4e055e09ddf8e3da3 100644 (file)
@@ -121,7 +121,7 @@ config ARCH_HAS_CACHE_LINE_SIZE
        def_bool y
 
 config HAVE_SETUP_PER_CPU_AREA
-       def_bool X86_64 || (X86_SMP && !X86_VOYAGER)
+       def_bool X86_64_SMP || (X86_SMP && !X86_VOYAGER)
 
 config HAVE_CPUMASK_OF_CPU_MAP
        def_bool X86_64_SMP
@@ -181,12 +181,12 @@ config X86_64_SMP
 config X86_HT
        bool
        depends on SMP
-       depends on (X86_32 && !(X86_VISWS || X86_VOYAGER)) || X86_64
+       depends on (X86_32 && !X86_VOYAGER) || X86_64
        default y
 
 config X86_BIOS_REBOOT
        bool
-       depends on !X86_VISWS && !X86_VOYAGER
+       depends on !X86_VOYAGER
        default y
 
 config X86_TRAMPOLINE
@@ -230,6 +230,26 @@ config SMP
 
          If you don't know what to do here, say N.
 
+config X86_FIND_SMP_CONFIG
+       def_bool y
+       depends on X86_MPPARSE || X86_VOYAGER
+
+if ACPI
+config X86_MPPARSE
+       def_bool y
+       bool "Enable MPS table"
+       depends on X86_LOCAL_APIC
+       help
+         For old smp systems that do not have proper acpi support. Newer systems
+         (esp with 64bit cpus) with acpi support, MADT and DSDT will override it
+endif
+
+if !ACPI
+config X86_MPPARSE
+       def_bool y
+       depends on X86_LOCAL_APIC
+endif
+
 choice
        prompt "Subarchitecture Type"
        default X86_PC
@@ -251,7 +271,7 @@ config X86_ELAN
 
 config X86_VOYAGER
        bool "Voyager (NCR)"
-       depends on X86_32 && (SMP || BROKEN)
+       depends on X86_32 && (SMP || BROKEN) && !PCI
        help
          Voyager is an MCA-based 32-way capable SMP architecture proprietary
          to NCR Corp.  Machine classes 345x/35xx/4100/51xx are Voyager-based.
@@ -261,16 +281,27 @@ config X86_VOYAGER
          If you do not specifically know you have a Voyager based machine,
          say N here, otherwise the kernel you build will not be bootable.
 
+config X86_GENERICARCH
+       bool "Generic architecture"
+       depends on X86_32
+       help
+          This option compiles in the NUMAQ, Summit, bigsmp, ES7000, default
+         subarchitectures.  It is intended for a generic binary kernel.
+         if you select them all, kernel will probe it one by one. and will
+         fallback to default.
+
+if X86_GENERICARCH
+
 config X86_NUMAQ
        bool "NUMAQ (IBM/Sequent)"
-       depends on SMP && X86_32
+       depends on SMP && X86_32 && PCI && X86_MPPARSE
        select NUMA
        help
-         This option is used for getting Linux to run on a (IBM/Sequent) NUMA
-         multiquad box. This changes the way that processors are bootstrapped,
-         and uses Clustered Logical APIC addressing mode instead of Flat Logical.
-         You will need a new lynxer.elf file to flash your firmware with - send
-         email to <Martin.Bligh@us.ibm.com>.
+         This option is used for getting Linux to run on a NUMAQ (IBM/Sequent)
+         NUMA multiquad box. This changes the way that processors are
+         bootstrapped, and uses Clustered Logical APIC addressing mode instead
+         of Flat Logical.  You will need a new lynxer.elf file to flash your
+         firmware with - send email to <Martin.Bligh@us.ibm.com>.
 
 config X86_SUMMIT
        bool "Summit/EXA (IBM x440)"
@@ -279,46 +310,21 @@ config X86_SUMMIT
          This option is needed for IBM systems that use the Summit/EXA chipset.
          In particular, it is needed for the x440.
 
-         If you don't have one of these computers, you should say N here.
-         If you want to build a NUMA kernel, you must select ACPI.
+config X86_ES7000
+       bool "Support for Unisys ES7000 IA32 series"
+       depends on X86_32 && SMP
+       help
+         Support for Unisys ES7000 systems.  Say 'Y' here if this kernel is
+         supposed to run on an IA32-based Unisys ES7000 system.
 
 config X86_BIGSMP
-       bool "Support for other sub-arch SMP systems with more than 8 CPUs"
+       bool "Support for big SMP systems with more than 8 CPUs"
        depends on X86_32 && SMP
        help
          This option is needed for the systems that have more than 8 CPUs
          and if the system is not of any sub-arch type above.
 
-         If you don't have such a system, you should say N here.
-
-config X86_VISWS
-       bool "SGI 320/540 (Visual Workstation)"
-       depends on X86_32
-       help
-         The SGI Visual Workstation series is an IA32-based workstation
-         based on SGI systems chips with some legacy PC hardware attached.
-
-         Say Y here to create a kernel to run on the SGI 320 or 540.
-
-         A kernel compiled for the Visual Workstation will not run on PCs
-         and vice versa. See <file:Documentation/sgi-visws.txt> for details.
-
-config X86_GENERICARCH
-       bool "Generic architecture (Summit, bigsmp, ES7000, default)"
-       depends on X86_32
-       help
-          This option compiles in the Summit, bigsmp, ES7000, default subarchitectures.
-         It is intended for a generic binary kernel.
-         If you want a NUMA kernel, select ACPI.   We need SRAT for NUMA.
-
-config X86_ES7000
-       bool "Support for Unisys ES7000 IA32 series"
-       depends on X86_32 && SMP
-       help
-         Support for Unisys ES7000 systems.  Say 'Y' here if this kernel is
-         supposed to run on an IA32-based Unisys ES7000 system.
-         Only choose this option if you have such a system, otherwise you
-         should say N here.
+endif
 
 config X86_RDC321X
        bool "RDC R-321x SoC"
@@ -337,7 +343,7 @@ config X86_RDC321X
 config X86_VSMP
        bool "Support for ScaleMP vSMP"
        select PARAVIRT
-       depends on X86_64
+       depends on X86_64 && PCI
        help
          Support for ScaleMP vSMP systems.  Say 'Y' here if this kernel is
          supposed to run on these EM64T-based machines.  Only choose this option
@@ -345,6 +351,18 @@ config X86_VSMP
 
 endchoice
 
+config X86_VISWS
+       bool "SGI 320/540 (Visual Workstation)"
+       depends on X86_32 && PCI && !X86_VOYAGER && X86_MPPARSE && PCI_GODIRECT
+       help
+         The SGI Visual Workstation series is an IA32-based workstation
+         based on SGI systems chips with some legacy PC hardware attached.
+
+         Say Y here to create a kernel to run on the SGI 320 or 540.
+
+         A kernel compiled for the Visual Workstation will run on general
+         PCs as well. See <file:Documentation/sgi-visws.txt> for details.
+
 config SCHED_NO_NO_OMIT_FRAME_POINTER
        def_bool y
        prompt "Single-depth WCHAN output"
@@ -373,7 +391,7 @@ config VMI
        bool "VMI Guest support"
        select PARAVIRT
        depends on X86_32
-       depends on !(X86_VISWS || X86_VOYAGER)
+       depends on !X86_VOYAGER
        help
          VMI provides a paravirtualized interface to the VMware ESX server
          (it could be used by other hypervisors in theory too, but is not
@@ -384,7 +402,7 @@ config KVM_CLOCK
        bool "KVM paravirtualized clock"
        select PARAVIRT
        select PARAVIRT_CLOCK
-       depends on !(X86_VISWS || X86_VOYAGER)
+       depends on !X86_VOYAGER
        help
          Turning on this option will allow you to run a paravirtualized clock
          when running over the KVM hypervisor. Instead of relying on a PIT
@@ -395,7 +413,7 @@ config KVM_CLOCK
 config KVM_GUEST
        bool "KVM Guest support"
        select PARAVIRT
-       depends on !(X86_VISWS || X86_VOYAGER)
+       depends on !X86_VOYAGER
        help
         This option enables various optimizations for running under the KVM
         hypervisor.
@@ -404,7 +422,7 @@ source "arch/x86/lguest/Kconfig"
 
 config PARAVIRT
        bool "Enable paravirtualization code"
-       depends on !(X86_VISWS || X86_VOYAGER)
+       depends on !X86_VOYAGER
        help
          This changes the kernel so it can modify itself when it is run
          under a hypervisor, potentially improving performance significantly
@@ -417,51 +435,33 @@ config PARAVIRT_CLOCK
 
 endif
 
-config MEMTEST_BOOTPARAM
-       bool "Memtest boot parameter"
+config PARAVIRT_DEBUG
+       bool "paravirt-ops debugging"
+       depends on PARAVIRT && DEBUG_KERNEL
+       help
+         Enable to debug paravirt_ops internals.  Specifically, BUG if
+        a paravirt_op is missing when it is called.
+
+config MEMTEST
+       bool "Memtest"
        depends on X86_64
        default y
        help
          This option adds a kernel parameter 'memtest', which allows memtest
-         to be disabled at boot.  If this option is selected, memtest
-         functionality can be disabled with memtest=0 on the kernel
-         command line.  The purpose of this option is to allow a single
-         kernel image to be distributed with memtest built in, but not
-         necessarily enabled.
-
+         to be set.
+               memtest=0, mean disabled; -- default
+               memtest=1, mean do 1 test pattern;
+               ...
+               memtest=4, mean do 4 test patterns.
          If you are unsure how to answer this question, answer Y.
 
-config MEMTEST_BOOTPARAM_VALUE
-       int "Memtest boot parameter default value (0-4)"
-       depends on MEMTEST_BOOTPARAM
-       range 0 4
-       default 0
-       help
-         This option sets the default value for the kernel parameter
-         'memtest', which allows memtest to be disabled at boot.  If this
-         option is set to 0 (zero), the memtest kernel parameter will
-         default to 0, disabling memtest at bootup.  If this option is
-         set to 4, the memtest kernel parameter will default to 4,
-         enabling memtest at bootup, and use that as pattern number.
-
-         If you are unsure how to answer this question, answer 0.
-
-config ACPI_SRAT
-       def_bool y
-       depends on X86_32 && ACPI && NUMA && (X86_SUMMIT || X86_GENERICARCH)
-       select ACPI_NUMA
-
-config HAVE_ARCH_PARSE_SRAT
-       def_bool y
-       depends on ACPI_SRAT
-
 config X86_SUMMIT_NUMA
        def_bool y
-       depends on X86_32 && NUMA && (X86_SUMMIT || X86_GENERICARCH)
+       depends on X86_32 && NUMA && X86_GENERICARCH
 
 config X86_CYCLONE_TIMER
        def_bool y
-       depends on X86_32 && X86_SUMMIT || X86_GENERICARCH
+       depends on X86_GENERICARCH
 
 config ES7000_CLUSTERED_APIC
        def_bool y
@@ -549,6 +549,21 @@ config CALGARY_IOMMU_ENABLED_BY_DEFAULT
          Calgary anyway, pass 'iommu=calgary' on the kernel command line.
          If unsure, say Y.
 
+config AMD_IOMMU
+       bool "AMD IOMMU support"
+       select SWIOTLB
+       depends on X86_64 && PCI && ACPI
+       help
+         With this option you can enable support for AMD IOMMU hardware in
+         your system. An IOMMU is a hardware component which provides
+         remapping of DMA memory accesses from devices. With an AMD IOMMU you
+         can isolate the the DMA memory of different devices and protect the
+         system from misbehaving device drivers or hardware.
+
+         You can find out if your system has an AMD IOMMU if you look into
+         your BIOS for an option to enable it or if you have an IVRS ACPI
+         table.
+
 # need this always selected by IOMMU for the VIA workaround
 config SWIOTLB
        bool
@@ -560,21 +575,36 @@ config SWIOTLB
          3 GB of memory. If unsure, say Y.
 
 config IOMMU_HELPER
-       def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB)
+       def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB || AMD_IOMMU)
+config MAXSMP
+       bool "Configure Maximum number of SMP Processors and NUMA Nodes"
+       depends on X86_64 && SMP
+       default n
+       help
+         Configure maximum number of CPUS and NUMA Nodes for this architecture.
+         If unsure, say N.
 
+if MAXSMP
 config NR_CPUS
-       int "Maximum number of CPUs (2-255)"
-       range 2 255
+       int
+       default "4096"
+endif
+
+if !MAXSMP
+config NR_CPUS
+       int "Maximum number of CPUs (2-4096)"
+       range 2 4096
        depends on SMP
        default "32" if X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000
        default "8"
        help
          This allows you to specify the maximum number of CPUs which this
-         kernel will support.  The maximum supported value is 255 and the
+         kernel will support.  The maximum supported value is 4096 and the
          minimum value which makes sense is 2.
 
          This is purely to save memory - each supported CPU adds
          approximately eight kilobytes to the kernel image.
+endif
 
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
@@ -598,7 +628,7 @@ source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
        bool "Local APIC support on uniprocessors"
-       depends on X86_32 && !SMP && !(X86_VISWS || X86_VOYAGER || X86_GENERICARCH)
+       depends on X86_32 && !SMP && !(X86_VOYAGER || X86_GENERICARCH)
        help
          A local APIC (Advanced Programmable Interrupt Controller) is an
          integrated interrupt controller in the CPU. If you have a single-CPU
@@ -623,11 +653,11 @@ config X86_UP_IOAPIC
 
 config X86_LOCAL_APIC
        def_bool y
-       depends on X86_64 || (X86_32 && (X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER) || X86_GENERICARCH))
+       depends on X86_64 || (X86_32 && (X86_UP_APIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
 
 config X86_IO_APIC
        def_bool y
-       depends on X86_64 || (X86_32 && (X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER)) || X86_GENERICARCH))
+       depends on X86_64 || (X86_32 && (X86_UP_IOAPIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
 
 config X86_VISWS_APIC
        def_bool y
@@ -681,7 +711,7 @@ config X86_MCE_NONFATAL
 
 config X86_MCE_P4THERMAL
        bool "check for P4 thermal throttling interrupt."
-       depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP) && !X86_VISWS
+       depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP)
        help
          Enabling this feature will cause a message to be printed when the P4
          enters thermal throttling.
@@ -911,9 +941,9 @@ config X86_PAE
 config NUMA
        bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)"
        depends on SMP
-       depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || (X86_SUMMIT || X86_GENERICARCH) && ACPI) && EXPERIMENTAL)
+       depends on X86_64 || (X86_32 && HIGHMEM64G && (X86_NUMAQ || X86_BIGSMP || X86_SUMMIT && ACPI) && EXPERIMENTAL)
        default n if X86_PC
-       default y if (X86_NUMAQ || X86_SUMMIT)
+       default y if (X86_NUMAQ || X86_SUMMIT || X86_BIGSMP)
        help
          Enable NUMA (Non Uniform Memory Access) support.
          The kernel will try to allocate memory used by a CPU on the
@@ -965,13 +995,25 @@ config NUMA_EMU
          into virtual nodes when booted with "numa=fake=N", where N is the
          number of nodes. This is only useful for debugging.
 
+if MAXSMP
+
+config NODES_SHIFT
+       int
+       default "9"
+endif
+
+if !MAXSMP
 config NODES_SHIFT
-       int "Max num nodes shift(1-9)"
-       range 1 9  if X86_64
+       int "Maximum NUMA Nodes (as a power of 2)"
+       range 1 9   if X86_64
        default "6" if X86_64
        default "4" if X86_NUMAQ
        default "3"
        depends on NEED_MULTIPLE_NODES
+       help
+         Specify the maximum number of NUMA Nodes available on the target
+         system.  Increases memory reserved to accomodate various tables.
+endif
 
 config HAVE_ARCH_BOOTMEM_NODE
        def_bool y
@@ -1090,6 +1132,40 @@ config MTRR
 
          See <file:Documentation/mtrr.txt> for more information.
 
+config MTRR_SANITIZER
+       def_bool y
+       prompt "MTRR cleanup support"
+       depends on MTRR
+       help
+         Convert MTRR layout from continuous to discrete, so some X driver
+         could add WB entries.
+
+         Say N here if you see bootup problems (boot crash, boot hang,
+         spontaneous reboots).
+
+         Could be disabled with disable_mtrr_cleanup. Also mtrr_chunk_size
+         could be used to send largest mtrr entry size for continuous block
+         to hold holes (aka. UC entries)
+
+         If unsure, say Y.
+
+config MTRR_SANITIZER_ENABLE_DEFAULT
+       int "MTRR cleanup enable value (0-1)"
+       range 0 1
+       default "0"
+       depends on MTRR_SANITIZER
+       help
+         Enable mtrr cleanup default value
+
+config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT
+       int "MTRR cleanup spare reg num (0-7)"
+       range 0 7
+       default "1"
+       depends on MTRR_SANITIZER
+       help
+         mtrr cleanup spare entries default, it can be changed via
+         mtrr_spare_reg_nr=
+
 config X86_PAT
        bool
        prompt "x86 PAT support"
@@ -1190,7 +1266,6 @@ config KEXEC
 
 config CRASH_DUMP
        bool "kernel crash dumps (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
        depends on X86_64 || (X86_32 && HIGHMEM)
        help
          Generate crash dump after being started by kexec.
@@ -1339,7 +1414,7 @@ config X86_APM_BOOT
 
 menuconfig APM
        tristate "APM (Advanced Power Management) BIOS support"
-       depends on X86_32 && PM_SLEEP && !X86_VISWS
+       depends on X86_32 && PM_SLEEP
        ---help---
          APM is a BIOS specification for saving power using several different
          techniques. This is mostly useful for battery powered laptops with
@@ -1475,8 +1550,7 @@ endmenu
 menu "Bus options (PCI etc.)"
 
 config PCI
-       bool "PCI support" if !X86_VISWS && !X86_VSMP
-       depends on !X86_VOYAGER
+       bool "PCI support"
        default y
        select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC)
        help
@@ -1487,7 +1561,7 @@ config PCI
 
 choice
        prompt "PCI access mode"
-       depends on X86_32 && PCI && !X86_VISWS
+       depends on X86_32 && PCI
        default PCI_GOANY
        ---help---
          On PCI systems, the BIOS can be used to detect the PCI devices and
@@ -1524,12 +1598,12 @@ endchoice
 
 config PCI_BIOS
        def_bool y
-       depends on X86_32 && !X86_VISWS && PCI && (PCI_GOBIOS || PCI_GOANY)
+       depends on X86_32 && PCI && (PCI_GOBIOS || PCI_GOANY)
 
 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
 config PCI_DIRECT
        def_bool y
-       depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
+       depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC))
 
 config PCI_MMCONFIG
        def_bool y
@@ -1589,7 +1663,7 @@ if X86_32
 
 config ISA
        bool "ISA support"
-       depends on !(X86_VOYAGER || X86_VISWS)
+       depends on !X86_VOYAGER
        help
          Find out whether you have ISA slots on your motherboard.  ISA is the
          name of a bus system, i.e. the way the CPU talks to the other stuff
@@ -1616,7 +1690,7 @@ config EISA
 source "drivers/eisa/Kconfig"
 
 config MCA
-       bool "MCA support" if !(X86_VISWS || X86_VOYAGER)
+       bool "MCA support" if !X86_VOYAGER
        default y if X86_VOYAGER
        help
          MicroChannel Architecture is found in some IBM PS/2 machines and
index 2ad6301849a1ba68ec78c9ea3c5f39232484c645..abff1b84ed5bf2e009908110a9de93cd783ca745 100644 (file)
@@ -344,7 +344,7 @@ config X86_F00F_BUG
 
 config X86_WP_WORKS_OK
        def_bool y
-       depends on X86_32 && !M386
+       depends on !M386
 
 config X86_INVLPG
        def_bool y
@@ -399,6 +399,10 @@ config X86_TSC
        def_bool y
        depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
 
+config X86_CMPXCHG64
+       def_bool y
+       depends on X86_PAE || X86_64
+
 # this should be set for all -march=.. options where the compiler
 # generates cmov.
 config X86_CMOV
index 18363374d51a9a57b39b6fb8d3f87a054b4b4aa5..acc0271920f2e3d80be6a50bb882066727e297e5 100644 (file)
@@ -20,6 +20,14 @@ config NONPROMISC_DEVMEM
 
          If in doubt, say Y.
 
+config X86_VERBOSE_BOOTUP
+       bool "Enable verbose x86 bootup info messages"
+       default y
+       help
+         Enables the informational output from the decompression stage
+         (e.g. bzImage) of the boot. If you disable this you will still
+         see errors. Disable this if you want silent bootup.
+
 config EARLY_PRINTK
        bool "Early printk" if EMBEDDED
        default y
@@ -60,7 +68,7 @@ config DEBUG_PAGEALLOC
 config DEBUG_PER_CPU_MAPS
        bool "Debug access to per_cpu maps"
        depends on DEBUG_KERNEL
-       depends on X86_64_SMP
+       depends on X86_SMP
        default n
        help
          Say Y to verify that the per_cpu map being accessed has
@@ -129,15 +137,6 @@ config 4KSTACKS
          on the VM subsystem for higher order allocations. This option
          will also use IRQ stacks to compensate for the reduced stackspace.
 
-config X86_FIND_SMP_CONFIG
-       def_bool y
-       depends on X86_LOCAL_APIC || X86_VOYAGER
-       depends on X86_32
-
-config X86_MPPARSE
-       def_bool y
-       depends on (X86_32 && (X86_LOCAL_APIC && !X86_VISWS)) || X86_64
-
 config DOUBLEFAULT
        default y
        bool "Enable doublefault exception handler" if EMBEDDED
index 3cff3c894cf3c0cd80161d1f61a959cbb80f7106..919ce21ea6545592fb10ce10461d0d1f053a3d00 100644 (file)
@@ -113,33 +113,11 @@ mcore-y  := arch/x86/mach-default/
 mflags-$(CONFIG_X86_VOYAGER)   := -Iinclude/asm-x86/mach-voyager
 mcore-$(CONFIG_X86_VOYAGER)    := arch/x86/mach-voyager/
 
-# VISWS subarch support
-mflags-$(CONFIG_X86_VISWS)     := -Iinclude/asm-x86/mach-visws
-mcore-$(CONFIG_X86_VISWS)      := arch/x86/mach-visws/
-
-# NUMAQ subarch support
-mflags-$(CONFIG_X86_NUMAQ)     := -Iinclude/asm-x86/mach-numaq
-mcore-$(CONFIG_X86_NUMAQ)      := arch/x86/mach-default/
-
-# BIGSMP subarch support
-mflags-$(CONFIG_X86_BIGSMP)    := -Iinclude/asm-x86/mach-bigsmp
-mcore-$(CONFIG_X86_BIGSMP)     := arch/x86/mach-default/
-
-#Summit subarch support
-mflags-$(CONFIG_X86_SUMMIT)    := -Iinclude/asm-x86/mach-summit
-mcore-$(CONFIG_X86_SUMMIT)     := arch/x86/mach-default/
-
 # generic subarchitecture
 mflags-$(CONFIG_X86_GENERICARCH):= -Iinclude/asm-x86/mach-generic
 fcore-$(CONFIG_X86_GENERICARCH)        += arch/x86/mach-generic/
 mcore-$(CONFIG_X86_GENERICARCH)        := arch/x86/mach-default/
 
-
-# ES7000 subarch support
-mflags-$(CONFIG_X86_ES7000)    := -Iinclude/asm-x86/mach-es7000
-fcore-$(CONFIG_X86_ES7000)     := arch/x86/mach-es7000/
-mcore-$(CONFIG_X86_ES7000)     := arch/x86/mach-default/
-
 # RDC R-321x subarch support
 mflags-$(CONFIG_X86_RDC321X)   := -Iinclude/asm-x86/mach-rdc321x
 mcore-$(CONFIG_X86_RDC321X)    := arch/x86/mach-default/
@@ -160,6 +138,7 @@ KBUILD_AFLAGS += $(mflags-y)
 
 head-y := arch/x86/kernel/head_$(BITS).o
 head-y += arch/x86/kernel/head$(BITS).o
+head-y += arch/x86/kernel/head.o
 head-y += arch/x86/kernel/init_task.o
 
 libs-y  += arch/x86/lib/
@@ -210,12 +189,12 @@ all: bzImage
 
 # KBUILD_IMAGE specify target image being built
                     KBUILD_IMAGE := $(boot)/bzImage
-zImage zlilo zdisk: KBUILD_IMAGE := arch/x86/boot/zImage
+zImage zlilo zdisk: KBUILD_IMAGE := $(boot)/zImage
 
 zImage bzImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
        $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
-       $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/bzImage
+       $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@
 
 compressed: zImage
 
index e01aafd03bdec42086147d4cb00e18a342a237eb..4063d630deff23cf2974e9839bc714de42b01f4c 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- linux-c -*- ------------------------------------------------------- *
  *
  *   Copyright (C) 1991, 1992 Linus Torvalds
- *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *   Copyright 2007-2008 rPath, Inc. - All Rights Reserved
  *
  *   This file is part of the Linux kernel, and is made available under
  *   the terms of the GNU General Public License version 2.
@@ -95,6 +95,9 @@ static void enable_a20_kbc(void)
 
        outb(0xdf, 0x60);       /* A20 on */
        empty_8042();
+
+       outb(0xff, 0x64);       /* Null command, but UHCI wants it */
+       empty_8042();
 }
 
 static void enable_a20_fast(void)
index d8819efac81dc4488ff59163172448710311cce0..1d5dff4123e15a3cebf9c59f6edaa9575c58dc70 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/page.h>
 #include <asm/boot.h>
 #include <asm/msr.h>
+#include <asm/processor-flags.h>
 #include <asm/asm-offsets.h>
 
 .section ".text.head"
@@ -109,7 +110,7 @@ startup_32:
 
        /* Enable PAE mode */
        xorl    %eax, %eax
-       orl     $(1 << 5), %eax
+       orl     $(X86_CR4_PAE), %eax
        movl    %eax, %cr4
 
  /*
@@ -170,7 +171,7 @@ startup_32:
        pushl   %eax
 
        /* Enter paged protected Mode, activating Long Mode */
-       movl    $0x80000001, %eax /* Enable Paging and Protected mode */
+       movl    $(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
        movl    %eax, %cr0
 
        /* Jump from 32bit compatibility mode into 64bit mode. */
index 90456cee47c337b226a8874582440377c428a91e..bc5553b496f719c665ed1e7876eae3e0f2d69b1a 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/boot.h>
+#include <asm/bootparam.h>
 
 /* WARNING!!
  * This code is compiled with -fPIC and it is relocated dynamically
@@ -187,13 +188,8 @@ static void gzip_release(void **);
 /*
  * This is set up by the setup-routine at boot-time
  */
-static unsigned char *real_mode; /* Pointer to real-mode data */
-
-#define RM_EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
-#ifndef STANDARD_MEMORY_BIOS_CALL
-#define RM_ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
-#endif
-#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
+static struct boot_params *real_mode;          /* Pointer to real-mode data */
+static int quiet;
 
 extern unsigned char input_data[];
 extern int input_len;
@@ -206,7 +202,8 @@ static void free(void *where);
 static void *memset(void *s, int c, unsigned n);
 static void *memcpy(void *dest, const void *src, unsigned n);
 
-static void putstr(const char *);
+static void __putstr(int, const char *);
+#define putstr(__x)  __putstr(0, __x)
 
 #ifdef CONFIG_X86_64
 #define memptr long
@@ -221,10 +218,6 @@ static char *vidmem;
 static int vidport;
 static int lines, cols;
 
-#ifdef CONFIG_X86_NUMAQ
-void *xquad_portio;
-#endif
-
 #include "../../../../lib/inflate.c"
 
 static void *malloc(int size)
@@ -270,18 +263,24 @@ static void scroll(void)
                vidmem[i] = ' ';
 }
 
-static void putstr(const char *s)
+static void __putstr(int error, const char *s)
 {
        int x, y, pos;
        char c;
 
+#ifndef CONFIG_X86_VERBOSE_BOOTUP
+       if (!error)
+               return;
+#endif
+
 #ifdef CONFIG_X86_32
-       if (RM_SCREEN_INFO.orig_video_mode == 0 && lines == 0 && cols == 0)
+       if (real_mode->screen_info.orig_video_mode == 0 &&
+           lines == 0 && cols == 0)
                return;
 #endif
 
-       x = RM_SCREEN_INFO.orig_x;
-       y = RM_SCREEN_INFO.orig_y;
+       x = real_mode->screen_info.orig_x;
+       y = real_mode->screen_info.orig_y;
 
        while ((c = *s++) != '\0') {
                if (c == '\n') {
@@ -302,8 +301,8 @@ static void putstr(const char *s)
                }
        }
 
-       RM_SCREEN_INFO.orig_x = x;
-       RM_SCREEN_INFO.orig_y = y;
+       real_mode->screen_info.orig_x = x;
+       real_mode->screen_info.orig_y = y;
 
        pos = (x + cols * y) * 2;       /* Update cursor position */
        outb(14, vidport);
@@ -366,9 +365,9 @@ static void flush_window(void)
 
 static void error(char *x)
 {
-       putstr("\n\n");
-       putstr(x);
-       putstr("\n\n -- System halted");
+       __putstr(1, "\n\n");
+       __putstr(1, x);
+       __putstr(1, "\n\n -- System halted");
 
        while (1)
                asm("hlt");
@@ -395,7 +394,8 @@ static void parse_elf(void *output)
                return;
        }
 
-       putstr("Parsing ELF... ");
+       if (!quiet)
+               putstr("Parsing ELF... ");
 
        phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
        if (!phdrs)
@@ -430,7 +430,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
 {
        real_mode = rmode;
 
-       if (RM_SCREEN_INFO.orig_video_mode == 7) {
+       if (real_mode->hdr.loadflags & QUIET_FLAG)
+               quiet = 1;
+
+       if (real_mode->screen_info.orig_video_mode == 7) {
                vidmem = (char *) 0xb0000;
                vidport = 0x3b4;
        } else {
@@ -438,8 +441,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
                vidport = 0x3d4;
        }
 
-       lines = RM_SCREEN_INFO.orig_video_lines;
-       cols = RM_SCREEN_INFO.orig_video_cols;
+       lines = real_mode->screen_info.orig_video_lines;
+       cols = real_mode->screen_info.orig_video_cols;
 
        window = output;                /* Output buffer (Normally at 1M) */
        free_mem_ptr     = heap;        /* Heap */
@@ -465,9 +468,11 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
 #endif
 
        makecrc();
-       putstr("\nDecompressing Linux... ");
+       if (!quiet)
+               putstr("\nDecompressing Linux... ");
        gunzip();
        parse_elf(output);
-       putstr("done.\nBooting the kernel.\n");
+       if (!quiet)
+               putstr("done.\nBooting the kernel.\n");
        return;
 }
index edaadea90aafcf9876256bcac9db5d68823874ea..a1310c52fc0c6ac6bf97feb276700e9f0662793e 100644 (file)
 #define USE_BSD
 #include <endian.h>
 
-#define MAX_SHDRS 100
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 static Elf32_Ehdr ehdr;
-static Elf32_Shdr shdr[MAX_SHDRS];
-static Elf32_Sym  *symtab[MAX_SHDRS];
-static Elf32_Rel  *reltab[MAX_SHDRS];
-static char *strtab[MAX_SHDRS];
 static unsigned long reloc_count, reloc_idx;
 static unsigned long *relocs;
 
+struct section {
+       Elf32_Shdr     shdr;
+       struct section *link;
+       Elf32_Sym      *symtab;
+       Elf32_Rel      *reltab;
+       char           *strtab;
+};
+static struct section *secs;
+
 /*
  * Following symbols have been audited. There values are constant and do
  * not change if bzImage is loaded at a different physical address than
@@ -35,7 +39,7 @@ static int is_safe_abs_reloc(const char* sym_name)
 {
        int i;
 
-       for(i = 0; i < ARRAY_SIZE(safe_abs_relocs); i++) {
+       for (i = 0; i < ARRAY_SIZE(safe_abs_relocs); i++) {
                if (!strcmp(sym_name, safe_abs_relocs[i]))
                        /* Match found */
                        return 1;
@@ -137,10 +141,10 @@ static const char *sec_name(unsigned shndx)
 {
        const char *sec_strtab;
        const char *name;
-       sec_strtab = strtab[ehdr.e_shstrndx];
+       sec_strtab = secs[ehdr.e_shstrndx].strtab;
        name = "<noname>";
        if (shndx < ehdr.e_shnum) {
-               name = sec_strtab + shdr[shndx].sh_name;
+               name = sec_strtab + secs[shndx].shdr.sh_name;
        }
        else if (shndx == SHN_ABS) {
                name = "ABSOLUTE";
@@ -159,7 +163,7 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
                name = sym_strtab + sym->st_name;
        }
        else {
-               name = sec_name(shdr[sym->st_shndx].sh_name);
+               name = sec_name(secs[sym->st_shndx].shdr.sh_name);
        }
        return name;
 }
@@ -244,29 +248,34 @@ static void read_ehdr(FILE *fp)
 static void read_shdrs(FILE *fp)
 {
        int i;
-       if (ehdr.e_shnum > MAX_SHDRS) {
-               die("%d section headers supported: %d\n",
-                       ehdr.e_shnum, MAX_SHDRS);
+       Elf32_Shdr shdr;
+
+       secs = calloc(ehdr.e_shnum, sizeof(struct section));
+       if (!secs) {
+               die("Unable to allocate %d section headers\n",
+                   ehdr.e_shnum);
        }
        if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
                die("Seek to %d failed: %s\n",
                        ehdr.e_shoff, strerror(errno));
        }
-       if (fread(&shdr, sizeof(shdr[0]), ehdr.e_shnum, fp) != ehdr.e_shnum) {
-               die("Cannot read ELF section headers: %s\n",
-                       strerror(errno));
-       }
-       for(i = 0; i < ehdr.e_shnum; i++) {
-               shdr[i].sh_name      = elf32_to_cpu(shdr[i].sh_name);
-               shdr[i].sh_type      = elf32_to_cpu(shdr[i].sh_type);
-               shdr[i].sh_flags     = elf32_to_cpu(shdr[i].sh_flags);
-               shdr[i].sh_addr      = elf32_to_cpu(shdr[i].sh_addr);
-               shdr[i].sh_offset    = elf32_to_cpu(shdr[i].sh_offset);
-               shdr[i].sh_size      = elf32_to_cpu(shdr[i].sh_size);
-               shdr[i].sh_link      = elf32_to_cpu(shdr[i].sh_link);
-               shdr[i].sh_info      = elf32_to_cpu(shdr[i].sh_info);
-               shdr[i].sh_addralign = elf32_to_cpu(shdr[i].sh_addralign);
-               shdr[i].sh_entsize   = elf32_to_cpu(shdr[i].sh_entsize);
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               if (fread(&shdr, sizeof shdr, 1, fp) != 1)
+                       die("Cannot read ELF section headers %d/%d: %s\n",
+                           i, ehdr.e_shnum, strerror(errno));
+               sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
+               sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
+               sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
+               sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
+               sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
+               sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
+               sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
+               sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
+               sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
+               sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
+               if (sec->shdr.sh_link < ehdr.e_shnum)
+                       sec->link = &secs[sec->shdr.sh_link];
        }
 
 }
@@ -274,20 +283,22 @@ static void read_shdrs(FILE *fp)
 static void read_strtabs(FILE *fp)
 {
        int i;
-       for(i = 0; i < ehdr.e_shnum; i++) {
-               if (shdr[i].sh_type != SHT_STRTAB) {
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               if (sec->shdr.sh_type != SHT_STRTAB) {
                        continue;
                }
-               strtab[i] = malloc(shdr[i].sh_size);
-               if (!strtab[i]) {
+               sec->strtab = malloc(sec->shdr.sh_size);
+               if (!sec->strtab) {
                        die("malloc of %d bytes for strtab failed\n",
-                               shdr[i].sh_size);
+                               sec->shdr.sh_size);
                }
-               if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
+               if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
                        die("Seek to %d failed: %s\n",
-                               shdr[i].sh_offset, strerror(errno));
+                               sec->shdr.sh_offset, strerror(errno));
                }
-               if (fread(strtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
+               if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
+                   != sec->shdr.sh_size) {
                        die("Cannot read symbol table: %s\n",
                                strerror(errno));
                }
@@ -297,28 +308,31 @@ static void read_strtabs(FILE *fp)
 static void read_symtabs(FILE *fp)
 {
        int i,j;
-       for(i = 0; i < ehdr.e_shnum; i++) {
-               if (shdr[i].sh_type != SHT_SYMTAB) {
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               if (sec->shdr.sh_type != SHT_SYMTAB) {
                        continue;
                }
-               symtab[i] = malloc(shdr[i].sh_size);
-               if (!symtab[i]) {
+               sec->symtab = malloc(sec->shdr.sh_size);
+               if (!sec->symtab) {
                        die("malloc of %d bytes for symtab failed\n",
-                               shdr[i].sh_size);
+                               sec->shdr.sh_size);
                }
-               if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
+               if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
                        die("Seek to %d failed: %s\n",
-                               shdr[i].sh_offset, strerror(errno));
+                               sec->shdr.sh_offset, strerror(errno));
                }
-               if (fread(symtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
+               if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
+                   != sec->shdr.sh_size) {
                        die("Cannot read symbol table: %s\n",
                                strerror(errno));
                }
-               for(j = 0; j < shdr[i].sh_size/sizeof(symtab[i][0]); j++) {
-                       symtab[i][j].st_name  = elf32_to_cpu(symtab[i][j].st_name);
-                       symtab[i][j].st_value = elf32_to_cpu(symtab[i][j].st_value);
-                       symtab[i][j].st_size  = elf32_to_cpu(symtab[i][j].st_size);
-                       symtab[i][j].st_shndx = elf16_to_cpu(symtab[i][j].st_shndx);
+               for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+                       Elf32_Sym *sym = &sec->symtab[j];
+                       sym->st_name  = elf32_to_cpu(sym->st_name);
+                       sym->st_value = elf32_to_cpu(sym->st_value);
+                       sym->st_size  = elf32_to_cpu(sym->st_size);
+                       sym->st_shndx = elf16_to_cpu(sym->st_shndx);
                }
        }
 }
@@ -327,26 +341,29 @@ static void read_symtabs(FILE *fp)
 static void read_relocs(FILE *fp)
 {
        int i,j;
-       for(i = 0; i < ehdr.e_shnum; i++) {
-               if (shdr[i].sh_type != SHT_REL) {
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               if (sec->shdr.sh_type != SHT_REL) {
                        continue;
                }
-               reltab[i] = malloc(shdr[i].sh_size);
-               if (!reltab[i]) {
+               sec->reltab = malloc(sec->shdr.sh_size);
+               if (!sec->reltab) {
                        die("malloc of %d bytes for relocs failed\n",
-                               shdr[i].sh_size);
+                               sec->shdr.sh_size);
                }
-               if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) {
+               if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
                        die("Seek to %d failed: %s\n",
-                               shdr[i].sh_offset, strerror(errno));
+                               sec->shdr.sh_offset, strerror(errno));
                }
-               if (fread(reltab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) {
+               if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
+                   != sec->shdr.sh_size) {
                        die("Cannot read symbol table: %s\n",
                                strerror(errno));
                }
-               for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
-                       reltab[i][j].r_offset = elf32_to_cpu(reltab[i][j].r_offset);
-                       reltab[i][j].r_info   = elf32_to_cpu(reltab[i][j].r_info);
+               for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+                       Elf32_Rel *rel = &sec->reltab[j];
+                       rel->r_offset = elf32_to_cpu(rel->r_offset);
+                       rel->r_info   = elf32_to_cpu(rel->r_info);
                }
        }
 }
@@ -357,19 +374,21 @@ static void print_absolute_symbols(void)
        int i;
        printf("Absolute symbols\n");
        printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
-       for(i = 0; i < ehdr.e_shnum; i++) {
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
                char *sym_strtab;
                Elf32_Sym *sh_symtab;
                int j;
-               if (shdr[i].sh_type != SHT_SYMTAB) {
+
+               if (sec->shdr.sh_type != SHT_SYMTAB) {
                        continue;
                }
-               sh_symtab = symtab[i];
-               sym_strtab = strtab[shdr[i].sh_link];
-               for(j = 0; j < shdr[i].sh_size/sizeof(symtab[0][0]); j++) {
+               sh_symtab = sec->symtab;
+               sym_strtab = sec->link->strtab;
+               for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
                        Elf32_Sym *sym;
                        const char *name;
-                       sym = &symtab[i][j];
+                       sym = &sec->symtab[j];
                        name = sym_name(sym_strtab, sym);
                        if (sym->st_shndx != SHN_ABS) {
                                continue;
@@ -389,26 +408,27 @@ static void print_absolute_relocs(void)
 {
        int i, printed = 0;
 
-       for(i = 0; i < ehdr.e_shnum; i++) {
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               struct section *sec_applies, *sec_symtab;
                char *sym_strtab;
                Elf32_Sym *sh_symtab;
-               unsigned sec_applies, sec_symtab;
                int j;
-               if (shdr[i].sh_type != SHT_REL) {
+               if (sec->shdr.sh_type != SHT_REL) {
                        continue;
                }
-               sec_symtab  = shdr[i].sh_link;
-               sec_applies = shdr[i].sh_info;
-               if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) {
+               sec_symtab  = sec->link;
+               sec_applies = &secs[sec->shdr.sh_info];
+               if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
                        continue;
                }
-               sh_symtab = symtab[sec_symtab];
-               sym_strtab = strtab[shdr[sec_symtab].sh_link];
-               for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
+               sh_symtab  = sec_symtab->symtab;
+               sym_strtab = sec_symtab->link->strtab;
+               for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
                        Elf32_Rel *rel;
                        Elf32_Sym *sym;
                        const char *name;
-                       rel = &reltab[i][j];
+                       rel = &sec->reltab[j];
                        sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
                        name = sym_name(sym_strtab, sym);
                        if (sym->st_shndx != SHN_ABS) {
@@ -456,26 +476,28 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
 {
        int i;
        /* Walk through the relocations */
-       for(i = 0; i < ehdr.e_shnum; i++) {
+       for (i = 0; i < ehdr.e_shnum; i++) {
                char *sym_strtab;
                Elf32_Sym *sh_symtab;
-               unsigned sec_applies, sec_symtab;
+               struct section *sec_applies, *sec_symtab;
                int j;
-               if (shdr[i].sh_type != SHT_REL) {
+               struct section *sec = &secs[i];
+
+               if (sec->shdr.sh_type != SHT_REL) {
                        continue;
                }
-               sec_symtab  = shdr[i].sh_link;
-               sec_applies = shdr[i].sh_info;
-               if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) {
+               sec_symtab  = sec->link;
+               sec_applies = &secs[sec->shdr.sh_info];
+               if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
                        continue;
                }
-               sh_symtab = symtab[sec_symtab];
-               sym_strtab = strtab[shdr[sec_symtab].sh_link];
-               for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) {
+               sh_symtab = sec_symtab->symtab;
+               sym_strtab = sec->link->strtab;
+               for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
                        Elf32_Rel *rel;
                        Elf32_Sym *sym;
                        unsigned r_type;
-                       rel = &reltab[i][j];
+                       rel = &sec->reltab[j];
                        sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
                        r_type = ELF32_R_TYPE(rel->r_info);
                        /* Don't visit relocations to absolute symbols */
@@ -539,7 +561,7 @@ static void emit_relocs(int as_text)
                 */
                printf(".section \".data.reloc\",\"a\"\n");
                printf(".balign 4\n");
-               for(i = 0; i < reloc_count; i++) {
+               for (i = 0; i < reloc_count; i++) {
                        printf("\t .long 0x%08lx\n", relocs[i]);
                }
                printf("\n");
@@ -550,7 +572,7 @@ static void emit_relocs(int as_text)
                /* Print a stop */
                printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]);
                /* Now print each relocation */
-               for(i = 0; i < reloc_count; i++) {
+               for (i = 0; i < reloc_count; i++) {
                        buf[0] = (relocs[i] >>  0) & 0xff;
                        buf[1] = (relocs[i] >>  8) & 0xff;
                        buf[2] = (relocs[i] >> 16) & 0xff;
@@ -577,7 +599,7 @@ int main(int argc, char **argv)
        show_absolute_relocs = 0;
        as_text = 0;
        fname = NULL;
-       for(i = 1; i < argc; i++) {
+       for (i = 1; i < argc; i++) {
                char *arg = argv[i];
                if (*arg == '-') {
                        if (strcmp(argv[1], "--abs-syms") == 0) {
index 00e19edd852c60d8cc32a2b009a604938747dd77..92d6fd73dc7dff60681d6ab7dee1362fba783d70 100644 (file)
@@ -28,6 +28,8 @@ static char *cpu_name(int level)
        if (level == 64) {
                return "x86-64";
        } else {
+               if (level == 15)
+                       level = 6;
                sprintf(buf, "i%d86", level);
                return buf;
        }
index 77569a4a3be114aaca948d04b060ebd28c80c1a9..2296164b54d2abc3ad8edc343af2b76c830d6693 100644 (file)
@@ -165,6 +165,10 @@ void main(void)
        /* Set the video mode */
        set_video();
 
+       /* Parse command line for 'quiet' and pass it to decompressor. */
+       if (cmdline_find_option_bool("quiet"))
+               boot_params.hdr.loadflags |= QUIET_FLAG;
+
        /* Do the last things and invoke protected mode */
        go_to_protected_mode();
 }
index acad32eb4290861b1539553c1e8eb49f7ec82e92..53165c97336b21406f49307cb4932c87468d32d9 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include "boot.h"
+#include <linux/kernel.h>
 
 #define SMAP   0x534d4150      /* ASCII "SMAP" */
 
@@ -53,7 +54,7 @@ static int detect_memory_e820(void)
 
                count++;
                desc++;
-       } while (next && count < E820MAX);
+       } while (next && count < ARRAY_SIZE(boot_params.e820_map));
 
        return boot_params.e820_entries = count;
 }
index ab049d40a884d7ef44d32fb63e30c44ed6aedabf..141b6e20ed3124dc102104991367de8b4779be68 100644 (file)
@@ -33,6 +33,8 @@ protected_mode_jump:
        movw    %cs, %bx
        shll    $4, %ebx
        addl    %ebx, 2f
+       jmp     1f                      # Short jump to serialize on 386/486
+1:
 
        movw    $__BOOT_DS, %cx
        movw    $__BOOT_TSS, %di
@@ -40,8 +42,6 @@ protected_mode_jump:
        movl    %cr0, %edx
        orb     $X86_CR0_PE, %dl        # Protected mode
        movl    %edx, %cr0
-       jmp     1f                      # Short jump to serialize on 386/486
-1:
 
        # Transition to 32-bit mode
        .byte   0x66, 0xea              # ljmpl opcode
index 40ecb8d7688c3d5c8a7587aa8fce8bb7ea06d76b..b939cb476decf7d4d3089f6210c4fe3ecfb5f5be 100644 (file)
@@ -259,8 +259,7 @@ static int vga_probe(void)
        return mode_count[adapter];
 }
 
-__videocard video_vga =
-{
+__videocard video_vga = {
        .card_name      = "VGA",
        .probe          = vga_probe,
        .set_mode       = vga_set_mode,
index ad7ddaaff588aaa619010fabe29af2ee2559d54d..9bc34e2033ecf9ec0518f59210449a07414ad5a1 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-git14
-# Fri Jul 20 09:53:15 2007
+# Linux kernel version: 2.6.26-rc1
+# Sun May  4 19:59:02 2008
 #
+# CONFIG_64BIT is not set
 CONFIG_X86_32=y
+# CONFIG_X86_64 is not set
+CONFIG_X86=y
+CONFIG_DEFCONFIG_LIST="arch/x86/configs/i386_defconfig"
+# CONFIG_GENERIC_LOCKBREAK is not set
 CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
 CONFIG_CLOCKSOURCE_WATCHDOG=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_SEMAPHORE_SLEEPERS=y
-CONFIG_X86=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_FAST_CMPXCHG_LOCAL=y
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
-CONFIG_QUICKLIST=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_HWEIGHT=y
+# CONFIG_GENERIC_GPIO is not set
 CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-CONFIG_DMI=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME_VSYSCALL is not set
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+# CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ZONE_DMA32 is not set
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+# CONFIG_AUDIT_ARCH is not set
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_X86_SMP=y
+CONFIG_X86_32_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_X86_TRAMPOLINE=y
+CONFIG_KTIME_SCALAR=y
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=18
-# CONFIG_CPUSETS is not set
-CONFIG_SYSFS_DEPRECATED=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_AUDIT_TREE=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CPUSETS=y
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+# CONFIG_USER_SCHED is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+# CONFIG_CGROUP_MEM_RES_CTLR is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_PROC_PID_CPUSET=y
 CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -56,13 +105,15 @@ CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
@@ -76,6 +127,17 @@ CONFIG_SLUB_DEBUG=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_MARKERS=y
+# CONFIG_OPROFILE is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
@@ -87,10 +149,10 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_KMOD is not set
 CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
-CONFIG_LBD=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LBD is not set
+CONFIG_BLK_DEV_IO_TRACE=y
 # CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLK_DEV_BSG=y
 
 #
 # IO Schedulers
@@ -103,7 +165,8 @@ CONFIG_IOSCHED_CFQ=y
 # CONFIG_DEFAULT_DEADLINE is not set
 CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
 
 #
 # Processor type and features
@@ -111,18 +174,21 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_SMP=y
-# CONFIG_X86_PC is not set
+CONFIG_X86_PC=y
 # CONFIG_X86_ELAN is not set
 # CONFIG_X86_VOYAGER is not set
 # CONFIG_X86_NUMAQ is not set
 # CONFIG_X86_SUMMIT is not set
 # CONFIG_X86_BIGSMP is not set
 # CONFIG_X86_VISWS is not set
-CONFIG_X86_GENERICARCH=y
+# CONFIG_X86_GENERICARCH is not set
 # CONFIG_X86_ES7000 is not set
-# CONFIG_PARAVIRT is not set
-CONFIG_X86_CYCLONE_TIMER=y
+# CONFIG_X86_RDC321X is not set
+# CONFIG_X86_VSMP is not set
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_PARAVIRT_GUEST is not set
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
@@ -130,9 +196,8 @@ CONFIG_X86_CYCLONE_TIMER=y
 # CONFIG_M586MMX is not set
 # CONFIG_M686 is not set
 # CONFIG_MPENTIUMII is not set
-CONFIG_MPENTIUMIII=y
+# CONFIG_MPENTIUMIII is not set
 # CONFIG_MPENTIUMM is not set
-# CONFIG_MCORE2 is not set
 # CONFIG_MPENTIUM4 is not set
 # CONFIG_MK6 is not set
 # CONFIG_MK7 is not set
@@ -147,14 +212,14 @@ CONFIG_MPENTIUMIII=y
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_MVIAC7 is not set
-CONFIG_X86_GENERIC=y
+# CONFIG_MPSC is not set
+CONFIG_MCORE2=y
+# CONFIG_GENERIC_CPU is not set
+# CONFIG_X86_GENERIC is not set
+CONFIG_X86_CPU=y
 CONFIG_X86_CMPXCHG=y
-CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_L1_CACHE_SHIFT=6
 CONFIG_X86_XADD=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
@@ -162,106 +227,120 @@ CONFIG_X86_POPAD_OK=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_P6_NOP=y
 CONFIG_X86_TSC=y
-CONFIG_X86_CMOV=y
-CONFIG_X86_MINIMUM_CPU_FAMILY=4
+CONFIG_X86_MINIMUM_CPU_FAMILY=6
+CONFIG_X86_DEBUGCTLMSR=y
 CONFIG_HPET_TIMER=y
 CONFIG_HPET_EMULATE_RTC=y
-CONFIG_NR_CPUS=32
-CONFIG_SCHED_SMT=y
+CONFIG_DMI=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_NR_CPUS=4
+# CONFIG_SCHED_SMT is not set
 CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
-CONFIG_PREEMPT_BKL=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_X86_IO_APIC=y
-CONFIG_X86_MCE=y
-CONFIG_X86_MCE_NONFATAL=y
-CONFIG_X86_MCE_P4THERMAL=y
+# CONFIG_X86_MCE is not set
 CONFIG_VM86=y
 # CONFIG_TOSHIBA is not set
 # CONFIG_I8K is not set
 # CONFIG_X86_REBOOTFIXUPS is not set
-CONFIG_MICROCODE=y
-CONFIG_MICROCODE_OLD_INTERFACE=y
+# CONFIG_MICROCODE is not set
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
-
-#
-# Firmware Drivers
-#
-# CONFIG_EDD is not set
-# CONFIG_DELL_RBU is not set
-# CONFIG_DCDBAS is not set
-CONFIG_DMIID=y
 # CONFIG_NOHIGHMEM is not set
 CONFIG_HIGHMEM4G=y
 # CONFIG_HIGHMEM64G is not set
 CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_HIGHMEM=y
-CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_NEED_NODE_MEMMAP_SIZE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
 # CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+
+#
+# Memory hotplug is currently incompatible with Software Suspend
+#
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
-CONFIG_NR_QUICK=1
 CONFIG_VIRT_TO_BUS=y
 # CONFIG_HIGHPTE is not set
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
-# CONFIG_EFI is not set
+# CONFIG_X86_PAT is not set
+CONFIG_EFI=y
 # CONFIG_IRQBALANCE is not set
 CONFIG_SECCOMP=y
 # CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
+# CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-# CONFIG_KEXEC is not set
-# CONFIG_CRASH_DUMP is not set
-CONFIG_PHYSICAL_START=0x100000
-# CONFIG_RELOCATABLE is not set
-CONFIG_PHYSICAL_ALIGN=0x100000
-# CONFIG_HOTPLUG_CPU is not set
-CONFIG_COMPAT_VDSO=y
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_RELOCATABLE=y
+CONFIG_PHYSICAL_ALIGN=0x200000
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_COMPAT_VDSO is not set
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 
 #
-# Power management options (ACPI, APM)
+# Power management options
 #
 CONFIG_PM=y
-CONFIG_PM_LEGACY=y
-# CONFIG_PM_DEBUG is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_VERBOSE is not set
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_TRACE=y
+CONFIG_PM_TRACE_RTC=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_HIBERNATION=y
+CONFIG_PM_STD_PARTITION=""
 CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
 CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROCFS_POWER=y
+CONFIG_ACPI_SYSFS_POWER=y
+CONFIG_ACPI_PROC_EVENT=y
 CONFIG_ACPI_AC=y
 CONFIG_ACPI_BATTERY=y
 CONFIG_ACPI_BUTTON=y
 CONFIG_ACPI_FAN=y
-# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_DOCK=y
+# CONFIG_ACPI_BAY is not set
 CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_HOTPLUG_CPU=y
 CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_WMI is not set
 # CONFIG_ACPI_ASUS is not set
 # CONFIG_ACPI_TOSHIBA is not set
-CONFIG_ACPI_BLACKLIST_YEAR=2001
-CONFIG_ACPI_DEBUG=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+CONFIG_ACPI_BLACKLIST_YEAR=0
+# CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_SYSTEM=y
 CONFIG_X86_PM_TIMER=y
-# CONFIG_ACPI_CONTAINER is not set
+CONFIG_ACPI_CONTAINER=y
 # CONFIG_ACPI_SBS is not set
 # CONFIG_APM is not set
 
@@ -271,15 +350,17 @@ CONFIG_X86_PM_TIMER=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=y
 CONFIG_CPU_FREQ_DEBUG=y
-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_USERSPACE is not set
+# CONFIG_CPU_FREQ_STAT is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# 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=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 
 #
 # CPUFreq processor drivers
@@ -287,8 +368,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_X86_ACPI_CPUFREQ=y
 # CONFIG_X86_POWERNOW_K6 is not set
 # CONFIG_X86_POWERNOW_K7 is not set
-CONFIG_X86_POWERNOW_K8=y
-CONFIG_X86_POWERNOW_K8_ACPI=y
+# CONFIG_X86_POWERNOW_K8 is not set
 # CONFIG_X86_GX_SUSPMOD is not set
 # CONFIG_X86_SPEEDSTEP_CENTRINO is not set
 # CONFIG_X86_SPEEDSTEP_ICH is not set
@@ -302,43 +382,72 @@ CONFIG_X86_POWERNOW_K8_ACPI=y
 #
 # shared options
 #
-CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
 # CONFIG_X86_SPEEDSTEP_LIB is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
 
 #
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Bus options (PCI etc.)
 #
 CONFIG_PCI=y
 # CONFIG_PCI_GOBIOS is not set
 # CONFIG_PCI_GOMMCONFIG is not set
 # CONFIG_PCI_GODIRECT is not set
 CONFIG_PCI_GOANY=y
+# CONFIG_PCI_GOOLPC is not set
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
-# CONFIG_PCIEPORTBUS is not set
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCIEPORTBUS=y
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
-# CONFIG_HT_IRQ is not set
+CONFIG_HT_IRQ=y
 CONFIG_ISA_DMA_API=y
 # CONFIG_ISA is not set
 # CONFIG_MCA is not set
 # CONFIG_SCx200 is not set
+# CONFIG_OLPC is not set
 CONFIG_K8_NB=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-# CONFIG_HOTPLUG_PCI is not set
-
-#
-# Executable file formats
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_TOSHIBA=y
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=y
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_IBM is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# Executable file formats / Emulations
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
 
 #
 # Networking
@@ -349,59 +458,142 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=y
 # CONFIG_XFRM_SUB_POLICY is not set
 # CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER 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_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
 # CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 # 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=y
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
+# 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_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_INET_LRO=y
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
 CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_DEFAULT_BIC is not set
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
 CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
+CONFIG_TCP_MD5SIG=y
+# CONFIG_IP_VS is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
 # CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
 # CONFIG_INET6_IPCOMP is not set
 # CONFIG_IPV6_MIP6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
 CONFIG_INET6_XFRM_MODE_TRANSPORT=y
 CONFIG_INET6_XFRM_MODE_TUNNEL=y
-# CONFIG_INET6_XFRM_MODE_BEET is not set
+CONFIG_INET6_XFRM_MODE_BEET=y
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
 CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
+# CONFIG_IPV6_MROUTE is not set
+CONFIG_NETLABEL=y
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_NF_NAT_FTP=y
+CONFIG_NF_NAT_IRC=y
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+CONFIG_NF_NAT_SIP=y
+CONFIG_IP_NF_MANGLE=y
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_LOG=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
@@ -409,6 +601,7 @@ CONFIG_IPV6_SIT=y
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
+CONFIG_LLC=y
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -416,28 +609,99 @@ CONFIG_IPV6_SIT=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RR is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_INGRESS is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+# CONFIG_NET_EMATCH_U32 is not set
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_ACT=y
+# CONFIG_NET_ACT_POLICE is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+CONFIG_NET_SCH_FIFO=y
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_NET_TCPPROBE is not set
-# CONFIG_HAMRADIO is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+# CONFIG_AX25 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_FIB_RULES=y
 
 #
 # Wireless
 #
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
+CONFIG_CFG80211=y
+CONFIG_NL80211=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_MAC80211=y
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_NONE is not set
+
+#
+# Selecting 'y' for an algorithm will
+#
+
+#
+# build the algorithm into mac80211.
+#
+CONFIG_MAC80211_RC_DEFAULT="pid"
+CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT is not set
+# CONFIG_MAC80211_DEBUG is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -449,13 +713,15 @@ CONFIG_IPV6_SIT=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
+CONFIG_DEBUG_DEVRES=y
 # CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
 # CONFIG_MTD is not set
 # CONFIG_PARPORT is not set
 CONFIG_PNP=y
@@ -466,7 +732,7 @@ CONFIG_PNP=y
 #
 CONFIG_PNPACPI=y
 CONFIG_BLK_DEV=y
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -479,8 +745,8 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 CONFIG_MISC_DEVICES=y
@@ -489,73 +755,17 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
+# CONFIG_ACER_WMI is not set
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_FUJITSU_LAPTOP is not set
+# CONFIG_TC1100_WMI is not set
+# CONFIG_MSI_LAPTOP is not set
 # CONFIG_SONY_LAPTOP is not set
 # CONFIG_THINKPAD_ACPI is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-CONFIG_BLK_DEV_IDEACPI=y
-# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_ONLYDISK is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-CONFIG_BLK_DEV_AMD74XX=y
-# CONFIG_BLK_DEV_ATIIXP is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_CS5535 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
@@ -564,8 +774,8 @@ CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
-CONFIG_SCSI_NETLINK=y
-# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -574,7 +784,7 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
-# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 # CONFIG_CHR_DEV_SCH is not set
 
@@ -582,7 +792,7 @@ CONFIG_CHR_DEV_SG=y
 # 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_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
 CONFIG_SCSI_WAIT_SCAN=m
@@ -591,81 +801,37 @@ CONFIG_SCSI_WAIT_SCAN=m
 # SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-CONFIG_BLK_DEV_3W_XXXX_RAID=y
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-CONFIG_SCSI_AIC7XXX=y
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
-CONFIG_AIC7XXX_RESET_DELAY_MS=5000
-CONFIG_AIC7XXX_DEBUG_ENABLE=y
-CONFIG_AIC7XXX_DEBUG_MASK=0
-CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-CONFIG_SCSI_AIC79XX=y
-CONFIG_AIC79XX_CMDS_PER_DEVICE=32
-CONFIG_AIC79XX_RESET_DELAY_MS=4000
-# CONFIG_AIC79XX_DEBUG_ENABLE is not set
-CONFIG_AIC79XX_DEBUG_MASK=0
-# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 CONFIG_ATA_ACPI=y
+CONFIG_SATA_PMP=y
 CONFIG_SATA_AHCI=y
-CONFIG_SATA_SVW=y
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
 CONFIG_ATA_PIIX=y
 # CONFIG_SATA_MV is not set
-CONFIG_SATA_NV=y
+# CONFIG_SATA_NV is not set
 # CONFIG_PDC_ADMA is not set
 # CONFIG_SATA_QSTOR is not set
 # CONFIG_SATA_PROMISE is not set
 # CONFIG_SATA_SX4 is not set
-CONFIG_SATA_SIL=y
-# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIL is not set
 # CONFIG_SATA_SIS is not set
 # CONFIG_SATA_ULI is not set
-CONFIG_SATA_VIA=y
+# CONFIG_SATA_VIA is not set
 # CONFIG_SATA_VITESSE is not set
 # CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ACPI is not set
 # CONFIG_PATA_ALI is not set
-# CONFIG_PATA_AMD is not set
+CONFIG_PATA_AMD=y
 # CONFIG_PATA_ARTOP is not set
 # CONFIG_PATA_ATIIXP is not set
 # CONFIG_PATA_CMD640_PCI is not set
@@ -673,6 +839,7 @@ CONFIG_SATA_VIA=y
 # CONFIG_PATA_CS5520 is not set
 # CONFIG_PATA_CS5530 is not set
 # CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CS5536 is not set
 # CONFIG_PATA_CYPRESS is not set
 # CONFIG_PATA_EFAR is not set
 # CONFIG_ATA_GENERIC is not set
@@ -686,11 +853,14 @@ CONFIG_SATA_VIA=y
 # CONFIG_PATA_TRIFLEX is not set
 # CONFIG_PATA_MARVELL is not set
 # CONFIG_PATA_MPIIX is not set
-# CONFIG_PATA_OLDPIIX is not set
+CONFIG_PATA_OLDPIIX=y
 # CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
 # CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
 # CONFIG_PATA_OPTI is not set
 # CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
 # CONFIG_PATA_PDC_OLD is not set
 # CONFIG_PATA_RADISYS is not set
 # CONFIG_PATA_RZ1000 is not set
@@ -702,65 +872,42 @@ CONFIG_SATA_VIA=y
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
 CONFIG_MD=y
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_DEBUG is not set
 # CONFIG_DM_CRYPT is not set
 # CONFIG_DM_SNAPSHOT is not set
-# CONFIG_DM_MIRROR is not set
-# CONFIG_DM_ZERO is not set
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
 # CONFIG_DM_MULTIPATH is not set
 # CONFIG_DM_DELAY is not set
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
-CONFIG_FUSION_MAX_SGE=128
-# CONFIG_FUSION_CTL is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
 # CONFIG_FIREWIRE is not set
-CONFIG_IEEE1394=y
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-
-#
-# Controllers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=y
-
-#
-# Protocols
-#
-# CONFIG_IEEE1394_VIDEO1394 is not set
-# CONFIG_IEEE1394_SBP2 is not set
-# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set
-# CONFIG_IEEE1394_ETH1394 is not set
-# CONFIG_IEEE1394_DV1394 is not set
-CONFIG_IEEE1394_RAWIO=y
+# CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
 CONFIG_MACINTOSH_DRIVERS=y
-# CONFIG_MAC_EMUMOUSEBTN is not set
+CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
-CONFIG_NETDEVICES_MULTIQUEUE=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
 # 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_NET_SB1000 is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
@@ -770,38 +917,40 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 CONFIG_NET_VENDOR_3COM=y
-CONFIG_VORTEX=y
+# CONFIG_VORTEX is not set
 # CONFIG_TYPHOON is not set
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
+# CONFIG_TULIP is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
 # CONFIG_ULI526X is not set
+# CONFIG_PCMCIA_XIRCOM is not set
 # CONFIG_HP100 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_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-CONFIG_B44=y
+# CONFIG_B44 is not set
 CONFIG_FORCEDETH=y
 # CONFIG_FORCEDETH_NAPI is not set
-# CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=y
+# CONFIG_8139CP is not set
 CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_PIO=y
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_R6040 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -814,34 +963,75 @@ CONFIG_NETDEV_1000=y
 CONFIG_E1000=y
 # CONFIG_E1000_NAPI is not set
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
-CONFIG_R8169=y
-# CONFIG_R8169_NAPI is not set
+# CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 CONFIG_SKY2=y
+# CONFIG_SKY2_DEBUG is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
-CONFIG_BNX2=y
+# CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
 # CONFIG_MLX4_CORE is not set
-# CONFIG_TR is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_SFC is not set
+CONFIG_TR=y
+# CONFIG_IBMOL is not set
+# CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
+# CONFIG_TMS380TR is not set
 
 #
 # Wireless LAN
 #
 # CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_ATH5K=y
+# CONFIG_ATH5K_DEBUG is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWLCORE is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_IWL4965 is not set
+# CONFIG_IWL3945 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
 
 #
 # USB Network Adapters
@@ -850,16 +1040,27 @@ CONFIG_NETDEV_10000=y
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_IBMTR is not set
 # CONFIG_WAN is not set
-# CONFIG_FDDI is not set
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+# CONFIG_SKFP is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 # CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
 CONFIG_NETPOLL=y
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
@@ -870,18 +1071,17 @@ CONFIG_NET_POLL_CONTROLLER=y
 # Input device support
 #
 CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=y
 
 #
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
@@ -906,17 +1106,63 @@ CONFIG_MOUSE_PS2_TRACKPOINT=y
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA 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
+CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDJOY is not set
+# CONFIG_JOYSTICK_ZHENHUA is not set
+# CONFIG_JOYSTICK_JOYDUMP is not set
+# CONFIG_JOYSTICK_XPAD is not set
+CONFIG_INPUT_TABLET=y
+# CONFIG_TABLET_USB_ACECAD is not set
+# CONFIG_TABLET_USB_AIPTEK is not set
+# CONFIG_TABLET_USB_GTCO is not set
+# CONFIG_TABLET_USB_KBTAB is not set
+# CONFIG_TABLET_USB_WACOM is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_WISTRON_BTNS is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Hardware I/O ports
 #
 CONFIG_SERIO=y
 CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
 CONFIG_SERIO_LIBPS2=y
@@ -929,8 +1175,26 @@ CONFIG_SERIO_LIBPS2=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_NOZOMI is not set
 
 #
 # Serial drivers
@@ -940,9 +1204,14 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_FIX_EARLYCON_MEM=y
 CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=32
 CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
 
 #
 # Non-8250 serial port support
@@ -951,89 +1220,275 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_INTEL=y
-CONFIG_HW_RANDOM_AMD=y
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_AMD is not set
 CONFIG_HW_RANDOM_GEODE=y
 CONFIG_HW_RANDOM_VIA=y
-# CONFIG_NVRAM is not set
-CONFIG_RTC=y
+CONFIG_NVRAM=y
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_SONYPI is not set
-CONFIG_AGP=y
-# CONFIG_AGP_ALI is not set
-# CONFIG_AGP_ATI is not set
-# CONFIG_AGP_AMD is not set
-CONFIG_AGP_AMD64=y
-CONFIG_AGP_INTEL=y
-# CONFIG_AGP_NVIDIA is not set
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_SWORKS is not set
-# CONFIG_AGP_VIA is not set
-# CONFIG_AGP_EFFICEON is not set
-# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
 # CONFIG_MWAVE is not set
 # CONFIG_PC8736x_GPIO is not set
 # CONFIG_NSC_GPIO is not set
 # CONFIG_CS5535_GPIO is not set
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=256
+# CONFIG_RAW_DRIVER is not set
 CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
-CONFIG_HPET_MMAP=y
+# CONFIG_HPET_MMAP is not set
 # CONFIG_HANGCHECK_TIMER is not set
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
 CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_I2C_I801=y
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 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
+# 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_SPI_MASTER is not set
 # CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
 # CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_IBMASR is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_ITCO_WDT is not set
+# CONFIG_IT8712F_WDT is not set
+# CONFIG_HP_WATCHDOG is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_PC87413_WDT is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_SBC7240_WDT is not set
+# CONFIG_CPU5_WDT is not set
+# CONFIG_SMSC37B787_WDT is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83697HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_SBC_EPX_C3_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
 # Multifunction device drivers
 #
 # CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
 
 #
 # Multimedia devices
 #
+
+#
+# Multimedia core support
+#
 # CONFIG_VIDEO_DEV is not set
 # CONFIG_DVB_CORE is not set
+
+#
+# Multimedia drivers
+#
 CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_AGP=y
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_ATI is not set
+# CONFIG_AGP_AMD is not set
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_NVIDIA is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_SWORKS is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_EFFICEON is not set
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_R128 is not set
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I830 is not set
+CONFIG_DRM_I915=y
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+# 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_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+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=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VESA is not set
+CONFIG_FB_EFI=y
+# CONFIG_FB_IMAC is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I810 is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# 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
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CORGI is not set
+# CONFIG_BACKLIGHT_PROGEAR is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
 
 #
 # Console display driver support
 #
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
-CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=128
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
 CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
 
 #
 # Sound
@@ -1043,33 +1498,167 @@ CONFIG_SOUND=y
 #
 # Advanced Linux Sound Architecture
 #
-# CONFIG_SND is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_SEQ_DUMMY=y
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+
+#
+# Generic devices
+#
+# CONFIG_SND_PCSP is not set
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+CONFIG_SND_HDA_INTEL=y
+CONFIG_SND_HDA_HWDEP=y
+CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_CODEC_ANALOG=y
+CONFIG_SND_HDA_CODEC_SIGMATEL=y
+CONFIG_SND_HDA_CODEC_VIA=y
+CONFIG_SND_HDA_CODEC_ATIHDMI=y
+CONFIG_SND_HDA_CODEC_CONEXANT=y
+CONFIG_SND_HDA_CODEC_CMEDIA=y
+CONFIG_SND_HDA_CODEC_SI3054=y
+CONFIG_SND_HDA_GENERIC=y
+# CONFIG_SND_HDA_POWER_SAVE is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
 
 #
 # Open Sound System
 #
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
+CONFIG_HID_DEBUG=y
+CONFIG_HIDRAW=y
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_PANTHERLORD_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB_HIDDEV=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
 # Miscellaneous USB options
@@ -1077,18 +1666,18 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_PERSIST is not set
+CONFIG_USB_SUSPEND=y
 # CONFIG_USB_OTG is not set
 
 #
 # USB Host Controller Drivers
 #
+# CONFIG_USB_C67X00_HCD is not set
 CONFIG_USB_EHCI_HCD=y
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
 # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1121,8 +1710,10 @@ CONFIG_USB_STORAGE=y
 # 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_LIBUSUAL is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
 
 #
 # USB Imaging devices
@@ -1134,10 +1725,6 @@ CONFIG_USB_MON=y
 #
 # USB port drivers
 #
-
-#
-# USB Serial Converter support
-#
 # CONFIG_USB_SERIAL is not set
 
 #
@@ -1163,90 +1750,125 @@ CONFIG_USB_MON=y
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 
 #
-# USB DSL modem support
+# LED drivers
 #
+# CONFIG_LEDS_CLEVO_MAIL is not set
 
 #
-# USB Gadget Support
+# LED Triggers
 #
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC=y
 
 #
-# LED devices
+# Reporting subsystems
 #
-# CONFIG_NEW_LEDS is not set
+# CONFIG_EDAC_DEBUG is not set
+# CONFIG_EDAC_MM_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_DEBUG is not set
 
 #
-# LED drivers
+# 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
 
 #
-# LED Triggers
+# I2C RTC drivers
 #
-# CONFIG_INFINIBAND is not set
-# CONFIG_EDAC is not set
+# 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
 
 #
-# Real Time Clock
+# SPI RTC drivers
 #
-# CONFIG_RTC_CLASS is not set
 
 #
-# DMA Engine support
+# Platform RTC drivers
 #
-# CONFIG_DMA_ENGINE is not set
+CONFIG_RTC_DRV_CMOS=y
+# 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_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# DMA Clients
+# on-CPU RTC drivers
 #
+CONFIG_DMADEVICES=y
 
 #
 # DMA Devices
 #
-CONFIG_VIRTUALIZATION=y
-# CONFIG_KVM is not set
+# CONFIG_INTEL_IOATDMA is not set
+# CONFIG_UIO is not set
 
 #
-# Userspace I/O
+# Firmware Drivers
 #
-# CONFIG_UIO is not set
+# CONFIG_EDD is not set
+CONFIG_EFI_VARS=y
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
+# CONFIG_ISCSI_IBFT_FIND is not set
 
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-# CONFIG_EXT2_FS_SECURITY is not set
-# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT2_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_SECURITY=y
 # CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=y
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-# CONFIG_REISERFS_FS_SECURITY is not set
+# CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
@@ -1256,8 +1878,8 @@ CONFIG_GENERIC_ACL=y
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
 # CONFIG_UDF_FS is not set
 
 #
@@ -1275,13 +1897,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_VMCORE=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -1289,6 +1911,7 @@ CONFIG_RAMFS=y
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -1296,33 +1919,15 @@ CONFIG_RAMFS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_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
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 is not set
-CONFIG_NFSD_TCP=y
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -1332,14 +1937,26 @@ CONFIG_SUNRPC=y
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
@@ -1374,37 +1991,33 @@ CONFIG_NLS_ISO8859_1=y
 # 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=y
+# CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=y
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
-CONFIG_INSTRUMENTATION=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-CONFIG_KPROBES=y
 
 #
 # 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=2048
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_UNUSED_SYMBOLS=y
-# CONFIG_DEBUG_FS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
-# CONFIG_SCHEDSTATS is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1419,48 +2032,174 @@ CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_LIST is not set
-# CONFIG_FRAME_POINTER is not set
-CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
+# CONFIG_SAMPLES is not set
+# CONFIG_KGDB is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_NONPROMISC_DEVMEM is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_RODATA is not set
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_PAGEALLOC 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_4KSTACKS is not set
 CONFIG_X86_FIND_SMP_CONFIG=y
 CONFIG_X86_MPPARSE=y
 CONFIG_DOUBLEFAULT=y
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+CONFIG_DEBUG_BOOT_PARAMS=y
+# CONFIG_CPA_DEBUG is not set
 
 #
 # Security options
 #
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_CRYPTO is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_FILE_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+# CONFIG_SECURITY_SMACK is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+# 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=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+CONFIG_CRYPTO_SHA1=y
+# 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=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# 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=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_586 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
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_PADLOCK is not set
+# CONFIG_CRYPTO_DEV_GEODE is not set
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_HAVE_KVM=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
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
+CONFIG_AUDIT_GENERIC=y
 CONFIG_ZLIB_INFLATE=y
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_PENDING_IRQ=y
-CONFIG_X86_SMP=y
-CONFIG_X86_HT=y
-CONFIG_X86_BIOS_REBOOT=y
-CONFIG_X86_TRAMPOLINE=y
-CONFIG_KTIME_SCALAR=y
index 2d6f5b2809d2f4644e82ccfd323acbe587693bf5..ae5124e064d4c881b0d5fa56f0826cdb00c7d8c4 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-git14
-# Fri Jul 20 09:53:15 2007
+# Linux kernel version: 2.6.26-rc1
+# Sun May  4 19:59:57 2008
 #
-CONFIG_X86_64=y
 CONFIG_64BIT=y
+# CONFIG_X86_32 is not set
+CONFIG_X86_64=y
 CONFIG_X86=y
+CONFIG_DEFCONFIG_LIST="arch/x86/configs/x86_64_defconfig"
+# CONFIG_GENERIC_LOCKBREAK is not set
 CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_TIME_VSYSCALL=y
 CONFIG_GENERIC_CMOS_UPDATE=y
-CONFIG_ZONE_DMA32=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_FAST_CMPXCHG_LOCAL=y
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
-CONFIG_QUICKLIST=y
-CONFIG_NR_QUICK=2
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_X86_CMPXCHG=y
-CONFIG_EARLY_PRINTK=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_GENERIC_IOMAP=y
-CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-CONFIG_ARCH_POPULATES_NODE_MAP=y
-CONFIG_DMI=y
-CONFIG_AUDIT_ARCH=y
 CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_CPUMASK_OF_CPU_MAP=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ZONE_DMA32=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_X86_SMP=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
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=18
-# CONFIG_CPUSETS is not set
-CONFIG_SYSFS_DEPRECATED=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_AUDIT_TREE=y
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CPUSETS=y
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+# CONFIG_USER_SCHED is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+# CONFIG_CGROUP_MEM_RES_CTLR is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_PROC_PID_CPUSET=y
 CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -66,13 +105,15 @@ CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
@@ -82,9 +123,21 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
 # CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_MARKERS=y
+# CONFIG_OPROFILE is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
@@ -96,14 +149,15 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_KMOD is not set
 CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_BLK_DEV_BSG is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLOCK_COMPAT=y
 
 #
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
 # CONFIG_DEFAULT_AS is not set
@@ -111,107 +165,177 @@ CONFIG_IOSCHED_CFQ=y
 CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
 
 #
 # Processor type and features
 #
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
 CONFIG_X86_PC=y
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_GENERICARCH is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_X86_RDC321X is not set
 # CONFIG_X86_VSMP is not set
+# CONFIG_PARAVIRT_GUEST is not set
+CONFIG_MEMTEST_BOOTPARAM=y
+CONFIG_MEMTEST_BOOTPARAM_VALUE=0
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
 # CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
 # CONFIG_MPSC is not set
-# CONFIG_MCORE2 is not set
-CONFIG_GENERIC_CPU=y
-CONFIG_X86_L1_CACHE_BYTES=128
-CONFIG_X86_L1_CACHE_SHIFT=7
-CONFIG_X86_INTERNODE_CACHE_BYTES=128
-CONFIG_X86_TSC=y
+CONFIG_MCORE2=y
+# CONFIG_GENERIC_CPU is not set
+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=6
 CONFIG_X86_GOOD_APIC=y
-# CONFIG_MICROCODE is not set
-CONFIG_X86_MSR=y
-CONFIG_X86_CPUID=y
-CONFIG_X86_HT=y
-CONFIG_X86_IO_APIC=y
-CONFIG_X86_LOCAL_APIC=y
-CONFIG_MTRR=y
-CONFIG_SMP=y
-CONFIG_SCHED_SMT=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_P6_NOP=y
+CONFIG_X86_TSC=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_DMI=y
+CONFIG_GART_IOMMU=y
+CONFIG_CALGARY_IOMMU=y
+CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT=y
+CONFIG_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_NR_CPUS=4
+# CONFIG_SCHED_SMT is not set
 CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_PREEMPT is not set
-CONFIG_PREEMPT_BKL=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+# CONFIG_X86_MCE is not set
+# CONFIG_I8K is not set
+# CONFIG_MICROCODE is not set
+CONFIG_X86_MSR=y
+CONFIG_X86_CPUID=y
 CONFIG_NUMA=y
 CONFIG_K8_NUMA=y
-CONFIG_NODES_SHIFT=6
 CONFIG_X86_64_ACPI_NUMA=y
-CONFIG_NUMA_EMU=y
+CONFIG_NODES_SPAN_OTHER_NODES=y
+# CONFIG_NUMA_EMU is not set
+CONFIG_NODES_SHIFT=6
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+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_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
 # CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+
+#
+# Memory hotplug is currently incompatible with Software Suspend
+#
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
-CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
-CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y
-CONFIG_NR_CPUS=32
-CONFIG_PHYSICAL_ALIGN=0x200000
-CONFIG_HOTPLUG_CPU=y
-CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-CONFIG_HPET_TIMER=y
-CONFIG_HPET_EMULATE_RTC=y
-CONFIG_GART_IOMMU=y
-# CONFIG_CALGARY_IOMMU is not set
-CONFIG_SWIOTLB=y
-CONFIG_X86_MCE=y
-CONFIG_X86_MCE_INTEL=y
-CONFIG_X86_MCE_AMD=y
-# CONFIG_KEXEC is not set
-# CONFIG_CRASH_DUMP is not set
-# CONFIG_RELOCATABLE is not set
-CONFIG_PHYSICAL_START=0x200000
+CONFIG_MTRR=y
+# CONFIG_X86_PAT is not set
+CONFIG_EFI=y
 CONFIG_SECCOMP=y
-# CONFIG_CC_STACKPROTECTOR is not set
 # CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
+# CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_K8_NB=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ISA_DMA_API=y
-CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_RELOCATABLE=y
+CONFIG_PHYSICAL_ALIGN=0x200000
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_COMPAT_VDSO is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
 
 #
 # Power management options
 #
+CONFIG_ARCH_HIBERNATION_HEADER=y
 CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_PM_DEBUG is not set
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_VERBOSE is not set
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_TRACE=y
+CONFIG_PM_TRACE_RTC=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
 CONFIG_HIBERNATION=y
 CONFIG_PM_STD_PARTITION=""
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
 CONFIG_ACPI=y
 CONFIG_ACPI_SLEEP=y
-CONFIG_ACPI_SLEEP_PROC_FS=y
-CONFIG_ACPI_SLEEP_PROC_SLEEP=y
 CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROCFS_POWER=y
+CONFIG_ACPI_SYSFS_POWER=y
+CONFIG_ACPI_PROC_EVENT=y
 CONFIG_ACPI_AC=y
 CONFIG_ACPI_BATTERY=y
 CONFIG_ACPI_BUTTON=y
 CONFIG_ACPI_FAN=y
-# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_DOCK=y
+# CONFIG_ACPI_BAY is not set
 CONFIG_ACPI_PROCESSOR=y
 CONFIG_ACPI_HOTPLUG_CPU=y
 CONFIG_ACPI_THERMAL=y
 CONFIG_ACPI_NUMA=y
+# CONFIG_ACPI_WMI is not set
 # CONFIG_ACPI_ASUS is not set
 # CONFIG_ACPI_TOSHIBA is not set
+# CONFIG_ACPI_CUSTOM_DSDT is not set
 CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
 CONFIG_ACPI_EC=y
@@ -227,29 +351,34 @@ CONFIG_ACPI_CONTAINER=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=y
 CONFIG_CPU_FREQ_DEBUG=y
-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_USERSPACE is not set
+# CONFIG_CPU_FREQ_STAT is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# 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=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 
 #
 # CPUFreq processor drivers
 #
-CONFIG_X86_POWERNOW_K8=y
-CONFIG_X86_POWERNOW_K8_ACPI=y
-# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
 CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_POWERNOW_K8 is not set
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+# CONFIG_X86_P4_CLOCKMOD is not set
 
 #
 # shared options
 #
-CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
+# CONFIG_X86_ACPI_CPUFREQ_PROC_INTF is not set
 # CONFIG_X86_SPEEDSTEP_LIB is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
 
 #
 # Bus options (PCI etc.)
@@ -257,27 +386,56 @@ CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
 CONFIG_PCI=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_DMAR=y
+CONFIG_DMAR_GFX_WA=y
+CONFIG_DMAR_FLOPPY_WA=y
 CONFIG_PCIEPORTBUS=y
+# CONFIG_HOTPLUG_PCI_PCIE is not set
 CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
-# CONFIG_HT_IRQ is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-# CONFIG_HOTPLUG_PCI is not set
+CONFIG_HT_IRQ=y
+CONFIG_ISA_DMA_API=y
+CONFIG_K8_NB=y
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_TOSHIBA=y
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=y
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
 
 #
 # Executable file formats / Emulations
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_COMPAT_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
 CONFIG_IA32_EMULATION=y
-CONFIG_IA32_AOUT=y
+# CONFIG_IA32_AOUT is not set
 CONFIG_COMPAT=y
+CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
 CONFIG_SYSVIPC_COMPAT=y
 
 #
@@ -289,22 +447,31 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER 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_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
 # CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
@@ -313,31 +480,109 @@ CONFIG_INET_TUNNEL=y
 # 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_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_INET_LRO=y
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
 CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_DEFAULT_BIC is not set
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
 CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
+CONFIG_TCP_MD5SIG=y
+# CONFIG_IP_VS is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
 # CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
 # CONFIG_INET6_IPCOMP is not set
 # CONFIG_IPV6_MIP6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
 CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
 # CONFIG_IPV6_TUNNEL is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
+# CONFIG_IPV6_MROUTE is not set
+CONFIG_NETLABEL=y
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_NF_NAT_FTP=y
+CONFIG_NF_NAT_IRC=y
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+CONFIG_NF_NAT_SIP=y
+CONFIG_IP_NF_MANGLE=y
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_LOG=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
@@ -345,6 +590,7 @@ CONFIG_IPV6_SIT=y
 # CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
+CONFIG_LLC=y
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -352,28 +598,99 @@ CONFIG_IPV6_SIT=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RR is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_INGRESS is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+# CONFIG_NET_EMATCH_U32 is not set
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_TEXT is not set
+CONFIG_NET_CLS_ACT=y
+# CONFIG_NET_ACT_POLICE is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+CONFIG_NET_SCH_FIFO=y
 
 #
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_NET_TCPPROBE is not set
-# CONFIG_HAMRADIO is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+# CONFIG_AX25 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_FIB_RULES=y
 
 #
 # Wireless
 #
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
+CONFIG_CFG80211=y
+CONFIG_NL80211=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_MAC80211=y
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_NONE is not set
+
+#
+# Selecting 'y' for an algorithm will
+#
+
+#
+# build the algorithm into mac80211.
+#
+CONFIG_MAC80211_RC_DEFAULT="pid"
+CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT is not set
+# CONFIG_MAC80211_DEBUG is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -385,13 +702,15 @@ CONFIG_IPV6_SIT=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-# CONFIG_DEBUG_DEVRES is not set
+CONFIG_DEBUG_DEVRES=y
 # CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
 # CONFIG_MTD is not set
 # CONFIG_PARPORT is not set
 CONFIG_PNP=y
@@ -402,7 +721,7 @@ CONFIG_PNP=y
 #
 CONFIG_PNPACPI=y
 CONFIG_BLK_DEV=y
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -415,8 +734,8 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 CONFIG_MISC_DEVICES=y
@@ -425,72 +744,16 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
+# CONFIG_ACER_WMI is not set
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_FUJITSU_LAPTOP is not set
+# CONFIG_MSI_LAPTOP is not set
 # CONFIG_SONY_LAPTOP is not set
 # CONFIG_THINKPAD_ACPI is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_IDEDISK_MULTI_MODE=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-CONFIG_BLK_DEV_IDEACPI=y
-# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_IDEPNP is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_IDEPCI_PCIBUS_ORDER=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_ONLYDISK is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_BLK_DEV_ATIIXP=y
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_JMICRON is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_IT8213 is not set
-# CONFIG_BLK_DEV_IT821X is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-CONFIG_BLK_DEV_PDC202XX_NEW=y
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIIMAGE is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_TC86C001 is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
@@ -499,8 +762,8 @@ CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_SCSI=y
 CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
-CONFIG_SCSI_NETLINK=y
-# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -509,7 +772,7 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
-# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 # CONFIG_CHR_DEV_SCH is not set
 
@@ -526,73 +789,37 @@ CONFIG_SCSI_WAIT_SCAN=m
 # SCSI Transports
 #
 CONFIG_SCSI_SPI_ATTRS=y
-CONFIG_SCSI_FC_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-CONFIG_SCSI_SAS_ATTRS=y
+# CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-CONFIG_SCSI_AIC79XX=y
-CONFIG_AIC79XX_CMDS_PER_DEVICE=32
-CONFIG_AIC79XX_RESET_DELAY_MS=4000
-# CONFIG_AIC79XX_DEBUG_ENABLE is not set
-CONFIG_AIC79XX_DEBUG_MASK=0
-# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
-# CONFIG_SCSI_AIC94XX is not set
-# CONFIG_SCSI_ARCMSR is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_STEX is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLA_FC is not set
-# CONFIG_SCSI_QLA_ISCSI is not set
-# CONFIG_SCSI_LPFC is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 CONFIG_ATA_ACPI=y
+CONFIG_SATA_PMP=y
 CONFIG_SATA_AHCI=y
-CONFIG_SATA_SVW=y
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
 CONFIG_ATA_PIIX=y
 # CONFIG_SATA_MV is not set
-CONFIG_SATA_NV=y
+# CONFIG_SATA_NV is not set
 # CONFIG_PDC_ADMA is not set
 # CONFIG_SATA_QSTOR is not set
 # CONFIG_SATA_PROMISE is not set
 # CONFIG_SATA_SX4 is not set
-CONFIG_SATA_SIL=y
-# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIL is not set
 # CONFIG_SATA_SIS is not set
 # CONFIG_SATA_ULI is not set
-CONFIG_SATA_VIA=y
+# CONFIG_SATA_VIA is not set
 # CONFIG_SATA_VITESSE is not set
 # CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ACPI is not set
 # CONFIG_PATA_ALI is not set
-# CONFIG_PATA_AMD is not set
+CONFIG_PATA_AMD=y
 # CONFIG_PATA_ARTOP is not set
 # CONFIG_PATA_ATIIXP is not set
 # CONFIG_PATA_CMD640_PCI is not set
@@ -612,11 +839,14 @@ CONFIG_SATA_VIA=y
 # CONFIG_PATA_TRIFLEX is not set
 # CONFIG_PATA_MARVELL is not set
 # CONFIG_PATA_MPIIX is not set
-# CONFIG_PATA_OLDPIIX is not set
+CONFIG_PATA_OLDPIIX=y
 # CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
 # CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
 # CONFIG_PATA_OPTI is not set
 # CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
 # CONFIG_PATA_PDC_OLD is not set
 # CONFIG_PATA_RADISYS is not set
 # CONFIG_PATA_RZ1000 is not set
@@ -628,65 +858,42 @@ CONFIG_SATA_VIA=y
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
 CONFIG_MD=y
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_DEBUG is not set
 # CONFIG_DM_CRYPT is not set
 # CONFIG_DM_SNAPSHOT is not set
-# CONFIG_DM_MIRROR is not set
-# CONFIG_DM_ZERO is not set
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
 # CONFIG_DM_MULTIPATH is not set
 # CONFIG_DM_DELAY is not set
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=y
-CONFIG_FUSION_SPI=y
-# CONFIG_FUSION_FC is not set
-# CONFIG_FUSION_SAS is not set
-CONFIG_FUSION_MAX_SGE=128
-# CONFIG_FUSION_CTL is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
 # CONFIG_FIREWIRE is not set
-CONFIG_IEEE1394=y
-
-#
-# Subsystem Options
-#
-# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-
-#
-# Controllers
-#
-
-#
-# Texas Instruments PCILynx requires I2C
-#
-CONFIG_IEEE1394_OHCI1394=y
-
-#
-# Protocols
-#
-# CONFIG_IEEE1394_VIDEO1394 is not set
-# CONFIG_IEEE1394_SBP2 is not set
-# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set
-# CONFIG_IEEE1394_ETH1394 is not set
-# CONFIG_IEEE1394_DV1394 is not set
-CONFIG_IEEE1394_RAWIO=y
+# CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
 CONFIG_MACINTOSH_DRIVERS=y
-# CONFIG_MAC_EMUMOUSEBTN is not set
+CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
-CONFIG_NETDEVICES_MULTIQUEUE=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
 # CONFIG_NET_SB1000 is not set
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
@@ -696,39 +903,40 @@ CONFIG_MII=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 CONFIG_NET_VENDOR_3COM=y
-CONFIG_VORTEX=y
+# CONFIG_VORTEX is not set
 # CONFIG_TYPHOON is not set
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
-CONFIG_TULIP=y
-# CONFIG_TULIP_MWI is not set
-# CONFIG_TULIP_MMIO is not set
-# CONFIG_TULIP_NAPI is not set
+# CONFIG_TULIP is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_DM9102 is not set
 # CONFIG_ULI526X is not set
+# CONFIG_PCMCIA_XIRCOM is not set
 # CONFIG_HP100 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_NET_PCI=y
 # CONFIG_PCNET32 is not set
-CONFIG_AMD8111_ETH=y
-# CONFIG_AMD8111E_NAPI is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
-CONFIG_B44=y
+# CONFIG_B44 is not set
 CONFIG_FORCEDETH=y
 # CONFIG_FORCEDETH_NAPI is not set
-# CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=y
+# CONFIG_8139CP is not set
 CONFIG_8139TOO=y
-# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_PIO=y
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_R6040 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -740,34 +948,74 @@ CONFIG_NETDEV_1000=y
 CONFIG_E1000=y
 # CONFIG_E1000_NAPI is not set
 # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
+CONFIG_SKY2=y
+# CONFIG_SKY2_DEBUG is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
-CONFIG_BNX2=y
+# CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
 CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
-CONFIG_S2IO=m
-# CONFIG_S2IO_NAPI is not set
+# CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
 # CONFIG_MLX4_CORE is not set
-# CONFIG_TR is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_SFC is not set
+CONFIG_TR=y
+# CONFIG_IBMOL is not set
+# CONFIG_3C359 is not set
+# CONFIG_TMS380TR is not set
 
 #
 # Wireless LAN
 #
 # CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_ATH5K=y
+# CONFIG_ATH5K_DEBUG is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWLCORE is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_IWL4965 is not set
+# CONFIG_IWL3945 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
 
 #
 # USB Network Adapters
@@ -776,16 +1024,26 @@ CONFIG_S2IO=m
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
 # CONFIG_USB_USBNET is not set
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
 # CONFIG_WAN is not set
-# CONFIG_FDDI is not set
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+# CONFIG_SKFP is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 # CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
 CONFIG_NETPOLL=y
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
@@ -796,18 +1054,17 @@ CONFIG_NET_POLL_CONTROLLER=y
 # Input device support
 #
 CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=y
 
 #
 # Userland interfaces
 #
 CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
 
@@ -832,17 +1089,62 @@ CONFIG_MOUSE_PS2_TRACKPOINT=y
 # CONFIG_MOUSE_SERIAL is not set
 # CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA 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
+CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDJOY is not set
+# CONFIG_JOYSTICK_ZHENHUA is not set
+# CONFIG_JOYSTICK_JOYDUMP is not set
+# CONFIG_JOYSTICK_XPAD is not set
+CONFIG_INPUT_TABLET=y
+# CONFIG_TABLET_USB_ACECAD is not set
+# CONFIG_TABLET_USB_AIPTEK is not set
+# CONFIG_TABLET_USB_GTCO is not set
+# CONFIG_TABLET_USB_KBTAB is not set
+# CONFIG_TABLET_USB_WACOM is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Hardware I/O ports
 #
 CONFIG_SERIO=y
 CONFIG_SERIO_I8042=y
-# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
 CONFIG_SERIO_LIBPS2=y
@@ -855,8 +1157,26 @@ CONFIG_SERIO_LIBPS2=y
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_NOZOMI is not set
 
 #
 # Serial drivers
@@ -866,9 +1186,14 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_FIX_EARLYCON_MEM=y
 CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_PNP=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=32
 CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
 
 #
 # Non-8250 serial port support
@@ -877,78 +1202,260 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
 CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_INTEL=y
-CONFIG_HW_RANDOM_AMD=y
-# CONFIG_NVRAM is not set
-CONFIG_RTC=y
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_AMD is not set
+CONFIG_NVRAM=y
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-CONFIG_AGP=y
-CONFIG_AGP_AMD64=y
-CONFIG_AGP_INTEL=y
-# CONFIG_AGP_SIS is not set
-# CONFIG_AGP_VIA is not set
-# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
 # CONFIG_MWAVE is not set
 # CONFIG_PC8736x_GPIO is not set
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=256
+# CONFIG_RAW_DRIVER is not set
 CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
-CONFIG_HPET_MMAP=y
+# CONFIG_HPET_MMAP is not set
 # CONFIG_HANGCHECK_TIMER is not set
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
 CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_I2C_I801=y
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 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
+# 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_SPI_MASTER is not set
 # CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
 # CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_IBMASR is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_ITCO_WDT is not set
+# CONFIG_IT8712F_WDT is not set
+# CONFIG_HP_WATCHDOG is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_PC87413_WDT is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_CPU5_WDT is not set
+# CONFIG_SMSC37B787_WDT is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83697HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_SBC_EPX_C3_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
 # Multifunction device drivers
 #
 # CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
 
 #
 # Multimedia devices
 #
+
+#
+# Multimedia core support
+#
 # CONFIG_VIDEO_DEV is not set
 # CONFIG_DVB_CORE is not set
+
+#
+# Multimedia drivers
+#
 CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_AGP=y
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_VIA is not set
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_R128 is not set
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I830 is not set
+CONFIG_DRM_I915=y
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+# 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_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+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=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VESA is not set
+CONFIG_FB_EFI=y
+# CONFIG_FB_IMAC is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CORGI is not set
+# CONFIG_BACKLIGHT_PROGEAR is not set
 
 #
 # Display device support
 #
 # CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-# CONFIG_FB is not set
 
 #
 # Console display driver support
 #
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
-CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=256
+CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
 CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
 
 #
 # Sound
@@ -958,33 +1465,165 @@ CONFIG_SOUND=y
 #
 # Advanced Linux Sound Architecture
 #
-# CONFIG_SND is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_SEQ_DUMMY=y
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+
+#
+# Generic devices
+#
+# CONFIG_SND_PCSP is not set
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+CONFIG_SND_HDA_INTEL=y
+CONFIG_SND_HDA_HWDEP=y
+CONFIG_SND_HDA_CODEC_REALTEK=y
+CONFIG_SND_HDA_CODEC_ANALOG=y
+CONFIG_SND_HDA_CODEC_SIGMATEL=y
+CONFIG_SND_HDA_CODEC_VIA=y
+CONFIG_SND_HDA_CODEC_ATIHDMI=y
+CONFIG_SND_HDA_CODEC_CONEXANT=y
+CONFIG_SND_HDA_CODEC_CMEDIA=y
+CONFIG_SND_HDA_CODEC_SI3054=y
+CONFIG_SND_HDA_GENERIC=y
+# CONFIG_SND_HDA_POWER_SAVE is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
 
 #
 # Open Sound System
 #
-CONFIG_SOUND_PRIME=y
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
+CONFIG_HID_DEBUG=y
+CONFIG_HIDRAW=y
 
 #
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_HIDINPUT_POWERBOOK=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_PANTHERLORD_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_ZEROPLUS_FF=y
+CONFIG_USB_HIDDEV=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
 # Miscellaneous USB options
@@ -992,18 +1631,18 @@ CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_PERSIST is not set
+CONFIG_USB_SUSPEND=y
 # CONFIG_USB_OTG is not set
 
 #
 # USB Host Controller Drivers
 #
+# CONFIG_USB_C67X00_HCD is not set
 CONFIG_USB_EHCI_HCD=y
-# CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
 # CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
@@ -1036,8 +1675,10 @@ CONFIG_USB_STORAGE=y
 # 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_LIBUSUAL is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_LIBUSUAL=y
 
 #
 # USB Imaging devices
@@ -1049,10 +1690,6 @@ CONFIG_USB_MON=y
 #
 # USB port drivers
 #
-
-#
-# USB Serial Converter support
-#
 # CONFIG_USB_SERIAL is not set
 
 #
@@ -1078,98 +1715,126 @@ CONFIG_USB_MON=y
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 
 #
-# USB DSL modem support
+# LED drivers
 #
+# CONFIG_LEDS_CLEVO_MAIL is not set
 
 #
-# USB Gadget Support
+# LED Triggers
 #
-# CONFIG_USB_GADGET is not set
-# CONFIG_MMC is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC=y
 
 #
-# LED devices
+# Reporting subsystems
 #
-# CONFIG_NEW_LEDS is not set
+# CONFIG_EDAC_DEBUG is not set
+# CONFIG_EDAC_MM_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_DEBUG is not set
 
 #
-# LED drivers
+# 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
 
 #
-# LED Triggers
+# I2C RTC drivers
 #
-# CONFIG_INFINIBAND is not set
-# CONFIG_EDAC is not set
+# 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
 
 #
-# Real Time Clock
+# SPI RTC drivers
 #
-# CONFIG_RTC_CLASS is not set
 
 #
-# DMA Engine support
+# Platform RTC drivers
 #
-# CONFIG_DMA_ENGINE is not set
+CONFIG_RTC_DRV_CMOS=y
+# 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_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
 
 #
-# DMA Clients
+# on-CPU RTC drivers
 #
+CONFIG_DMADEVICES=y
 
 #
 # DMA Devices
 #
-CONFIG_VIRTUALIZATION=y
-# CONFIG_KVM is not set
-
-#
-# Userspace I/O
-#
+# CONFIG_INTEL_IOATDMA is not set
 # CONFIG_UIO is not set
 
 #
 # Firmware Drivers
 #
 # CONFIG_EDD is not set
+CONFIG_EFI_VARS=y
 # CONFIG_DELL_RBU is not set
 # CONFIG_DCDBAS is not set
 CONFIG_DMIID=y
+# CONFIG_ISCSI_IBFT_FIND is not set
 
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-# CONFIG_EXT2_FS_SECURITY is not set
-# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT2_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_SECURITY=y
 # CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=y
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-# CONFIG_REISERFS_FS_SECURITY is not set
+# CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_FUSE_FS is not set
@@ -1180,7 +1845,7 @@ CONFIG_GENERIC_ACL=y
 #
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
+CONFIG_ZISOFS=y
 # CONFIG_UDF_FS is not set
 
 #
@@ -1198,13 +1863,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_PROC_VMCORE=y
 CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -1212,6 +1877,7 @@ CONFIG_RAMFS=y
 #
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
@@ -1219,33 +1885,15 @@ CONFIG_RAMFS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_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
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 is not set
-CONFIG_NFSD_TCP=y
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -1255,14 +1903,26 @@ CONFIG_SUNRPC=y
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_DEFAULT="utf8"
 CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
@@ -1297,40 +1957,33 @@ CONFIG_NLS_ISO8859_1=y
 # 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=y
+# CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=y
-
-#
-# Distributed Lock Manager
-#
 # CONFIG_DLM is not set
 
-#
-# Instrumentation Support
-#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-CONFIG_KPROBES=y
-
 #
 # 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=2048
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_UNUSED_SYMBOLS=y
+# CONFIG_UNUSED_SYMBOLS is not set
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
-# CONFIG_SCHEDSTATS is not set
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -1344,28 +1997,162 @@ CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
 # CONFIG_DEBUG_LIST is not set
-# CONFIG_FRAME_POINTER is not set
-CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
-# CONFIG_DEBUG_RODATA is not set
-# CONFIG_IOMMU_DEBUG is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
+# CONFIG_SAMPLES is not set
+# CONFIG_KGDB is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_NONPROMISC_DEVMEM is not set
+CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_DEBUG_STACK_USAGE is not set
+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_DIRECT_GBPAGES is not set
+# CONFIG_DEBUG_RODATA_TEST is not set
+CONFIG_DEBUG_NX_TEST=m
+CONFIG_X86_MPPARSE=y
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+CONFIG_DEBUG_BOOT_PARAMS=y
+# CONFIG_CPA_DEBUG is not set
 
 #
 # Security options
 #
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_CRYPTO is not set
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+CONFIG_SECURITY_CAPABILITIES=y
+CONFIG_SECURITY_FILE_CAPABILITIES=y
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT is not set
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+# CONFIG_SECURITY_SMACK is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+# 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=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+CONFIG_CRYPTO_SHA1=y
+# 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=y
+# CONFIG_CRYPTO_AES_X86_64 is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# 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=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_X86_64 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
+# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_HAVE_KVM=y
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTIO_BALLOON is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
index b5e329da166cfa2a48a74339a47539739ec939ac..20371d0635e44975850ea37b5a8a03a2f52f0d58 100644 (file)
        CFI_UNDEFINED   r15
        .endm
 
+#ifdef CONFIG_PARAVIRT
+ENTRY(native_usergs_sysret32)
+       swapgs
+       sysretl
+ENDPROC(native_usergs_sysret32)
+
+ENTRY(native_irq_enable_sysexit)
+       swapgs
+       sti
+       sysexit
+ENDPROC(native_irq_enable_sysexit)
+#endif
+
 /*
  * 32bit SYSENTER instruction entry.
  *
@@ -85,14 +98,14 @@ ENTRY(ia32_sysenter_target)
        CFI_SIGNAL_FRAME
        CFI_DEF_CFA     rsp,0
        CFI_REGISTER    rsp,rbp
-       swapgs
+       SWAPGS_UNSAFE_STACK
        movq    %gs:pda_kernelstack, %rsp
        addq    $(PDA_STACKOFFSET),%rsp 
        /*
         * No need to follow this irqs on/off section: the syscall
         * disabled irqs, here we enable it straight after entry:
         */
-       sti     
+       ENABLE_INTERRUPTS(CLBR_NONE)
        movl    %ebp,%ebp               /* zero extension */
        pushq   $__USER32_DS
        CFI_ADJUST_CFA_OFFSET 8
@@ -103,7 +116,7 @@ ENTRY(ia32_sysenter_target)
        pushfq
        CFI_ADJUST_CFA_OFFSET 8
        /*CFI_REL_OFFSET rflags,0*/
-       movl    8*3-THREAD_SIZE+threadinfo_sysenter_return(%rsp), %r10d
+       movl    8*3-THREAD_SIZE+TI_sysenter_return(%rsp), %r10d
        CFI_REGISTER rip,r10
        pushq   $__USER32_CS
        CFI_ADJUST_CFA_OFFSET 8
@@ -123,8 +136,9 @@ ENTRY(ia32_sysenter_target)
        .quad 1b,ia32_badarg
        .previous       
        GET_THREAD_INFO(%r10)
-       orl    $TS_COMPAT,threadinfo_status(%r10)
-       testl  $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
+       orl    $TS_COMPAT,TI_status(%r10)
+       testl  $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \
+                TI_flags(%r10)
        CFI_REMEMBER_STATE
        jnz  sysenter_tracesys
 sysenter_do_call:      
@@ -134,11 +148,11 @@ sysenter_do_call:
        call    *ia32_sys_call_table(,%rax,8)
        movq    %rax,RAX-ARGOFFSET(%rsp)
        GET_THREAD_INFO(%r10)
-       cli
+       DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
-       testl   $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
+       testl   $_TIF_ALLWORK_MASK,TI_flags(%r10)
        jnz     int_ret_from_sys_call
-       andl    $~TS_COMPAT,threadinfo_status(%r10)
+       andl    $~TS_COMPAT,TI_status(%r10)
        /* clear IF, that popfq doesn't enable interrupts early */
        andl  $~0x200,EFLAGS-R11(%rsp) 
        movl    RIP-R11(%rsp),%edx              /* User %eip */
@@ -151,10 +165,7 @@ sysenter_do_call:
        CFI_ADJUST_CFA_OFFSET -8
        CFI_REGISTER rsp,rcx
        TRACE_IRQS_ON
-       swapgs
-       sti             /* sti only takes effect after the next instruction */
-       /* sysexit */
-       .byte   0xf, 0x35
+       ENABLE_INTERRUPTS_SYSEXIT32
 
 sysenter_tracesys:
        CFI_RESTORE_STATE
@@ -200,7 +211,7 @@ ENTRY(ia32_cstar_target)
        CFI_DEF_CFA     rsp,PDA_STACKOFFSET
        CFI_REGISTER    rip,rcx
        /*CFI_REGISTER  rflags,r11*/
-       swapgs
+       SWAPGS_UNSAFE_STACK
        movl    %esp,%r8d
        CFI_REGISTER    rsp,r8
        movq    %gs:pda_kernelstack,%rsp
@@ -208,7 +219,7 @@ ENTRY(ia32_cstar_target)
         * No need to follow this irqs on/off section: the syscall
         * disabled irqs and here we enable it straight after entry:
         */
-       sti
+       ENABLE_INTERRUPTS(CLBR_NONE)
        SAVE_ARGS 8,1,1
        movl    %eax,%eax       /* zero extension */
        movq    %rax,ORIG_RAX-ARGOFFSET(%rsp)
@@ -230,8 +241,9 @@ ENTRY(ia32_cstar_target)
        .quad 1b,ia32_badarg
        .previous       
        GET_THREAD_INFO(%r10)
-       orl   $TS_COMPAT,threadinfo_status(%r10)
-       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
+       orl   $TS_COMPAT,TI_status(%r10)
+       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \
+               TI_flags(%r10)
        CFI_REMEMBER_STATE
        jnz   cstar_tracesys
 cstar_do_call: 
@@ -241,11 +253,11 @@ cstar_do_call:
        call *ia32_sys_call_table(,%rax,8)
        movq %rax,RAX-ARGOFFSET(%rsp)
        GET_THREAD_INFO(%r10)
-       cli
+       DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
-       testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10)
+       testl $_TIF_ALLWORK_MASK,TI_flags(%r10)
        jnz  int_ret_from_sys_call
-       andl $~TS_COMPAT,threadinfo_status(%r10)
+       andl $~TS_COMPAT,TI_status(%r10)
        RESTORE_ARGS 1,-ARG_SKIP,1,1,1
        movl RIP-ARGOFFSET(%rsp),%ecx
        CFI_REGISTER rip,rcx
@@ -254,8 +266,7 @@ cstar_do_call:
        TRACE_IRQS_ON
        movl RSP-ARGOFFSET(%rsp),%esp
        CFI_RESTORE rsp
-       swapgs
-       sysretl
+       USERGS_SYSRET32
        
 cstar_tracesys:        
        CFI_RESTORE_STATE
@@ -310,12 +321,12 @@ ENTRY(ia32_syscall)
        /*CFI_REL_OFFSET        rflags,EFLAGS-RIP*/
        /*CFI_REL_OFFSET        cs,CS-RIP*/
        CFI_REL_OFFSET  rip,RIP-RIP
-       swapgs
+       SWAPGS
        /*
         * No need to follow this irqs on/off section: the syscall
         * disabled irqs and here we enable it straight after entry:
         */
-       sti
+       ENABLE_INTERRUPTS(CLBR_NONE)
        movl %eax,%eax
        pushq %rax
        CFI_ADJUST_CFA_OFFSET 8
@@ -324,8 +335,9 @@ ENTRY(ia32_syscall)
           this could be a problem. */
        SAVE_ARGS 0,0,1
        GET_THREAD_INFO(%r10)
-       orl   $TS_COMPAT,threadinfo_status(%r10)
-       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10)
+       orl   $TS_COMPAT,TI_status(%r10)
+       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \
+               TI_flags(%r10)
        jnz ia32_tracesys
 ia32_do_syscall:       
        cmpl $(IA32_NR_syscalls-1),%eax
@@ -370,13 +382,11 @@ quiet_ni_syscall:
        PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
        PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
        PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
-       PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx
        PTREGSCALL stub32_execve, sys32_execve, %rcx
        PTREGSCALL stub32_fork, sys_fork, %rdi
        PTREGSCALL stub32_clone, sys32_clone, %rdx
        PTREGSCALL stub32_vfork, sys_vfork, %rdi
        PTREGSCALL stub32_iopl, sys_iopl, %rsi
-       PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx
 
 ENTRY(ia32_ptregs_common)
        popq %r11
@@ -476,7 +486,7 @@ ia32_sys_call_table:
        .quad sys_ssetmask
        .quad sys_setreuid16    /* 70 */
        .quad sys_setregid16
-       .quad stub32_sigsuspend
+       .quad sys32_sigsuspend
        .quad compat_sys_sigpending
        .quad sys_sethostname
        .quad compat_sys_setrlimit      /* 75 */
@@ -583,7 +593,7 @@ ia32_sys_call_table:
        .quad sys32_rt_sigpending
        .quad compat_sys_rt_sigtimedwait
        .quad sys32_rt_sigqueueinfo
-       .quad stub32_rt_sigsuspend
+       .quad sys_rt_sigsuspend
        .quad sys32_pread               /* 180 */
        .quad sys32_pwrite
        .quad sys_chown16
index 77807d4769c99c455237a810fe0edd0f996fb31f..55ff016e9f694f61d5dc143675797860a4f4de3d 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-extra-y                := head_$(BITS).o head$(BITS).o init_task.o vmlinux.lds
+extra-y                := head_$(BITS).o head$(BITS).o head.o init_task.o vmlinux.lds
 
 CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE)
 
@@ -13,20 +13,21 @@ CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE)
 nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_vsyscall_64.o   := $(PROFILING) -g0 $(nostackp)
 CFLAGS_hpet.o          := $(nostackp)
-CFLAGS_tsc_64.o                := $(nostackp)
+CFLAGS_tsc.o           := $(nostackp)
 
 obj-y                  := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
 obj-y                  += traps_$(BITS).o irq_$(BITS).o
 obj-y                  += time_$(BITS).o ioport.o ldt.o
-obj-y                  += setup_$(BITS).o i8259_$(BITS).o setup.o
+obj-y                  += setup.o i8259.o irqinit_$(BITS).o setup_percpu.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
 obj-$(CONFIG_X86_64)   += sys_x86_64.o x8664_ksyms_64.o
-obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o setup64.o
-obj-y                  += bootflag.o e820_$(BITS).o
+obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o
+obj-y                  += bootflag.o e820.o
 obj-y                  += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
 obj-y                  += alternative.o i8253.o pci-nommu.o
-obj-$(CONFIG_X86_64)   += bugs_64.o
-obj-y                  += tsc_$(BITS).o io_delay.o rtc.o
+obj-y                  += tsc.o io_delay.o rtc.o
 
 obj-$(CONFIG_X86_TRAMPOLINE)   += trampoline.o
 obj-y                          += process.o
@@ -53,7 +54,7 @@ obj-$(CONFIG_X86_32_SMP)      += smpcommon.o
 obj-$(CONFIG_X86_64_SMP)       += tsc_sync.o smpcommon.o
 obj-$(CONFIG_X86_TRAMPOLINE)   += trampoline_$(BITS).o
 obj-$(CONFIG_X86_MPPARSE)      += mpparse.o
-obj-$(CONFIG_X86_LOCAL_APIC)   += apic_$(BITS).o nmi_$(BITS).o
+obj-$(CONFIG_X86_LOCAL_APIC)   += apic_$(BITS).o nmi.o
 obj-$(CONFIG_X86_IO_APIC)      += io_apic_$(BITS).o
 obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
 obj-$(CONFIG_KEXEC)            += machine_kexec_$(BITS).o
@@ -64,7 +65,6 @@ obj-$(CONFIG_X86_SUMMIT_NUMA) += summit_32.o
 obj-y                          += vsmp_64.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_MODULES)          += module_$(BITS).o
-obj-$(CONFIG_ACPI_SRAT)        += srat_32.o
 obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
 obj-$(CONFIG_KGDB)             += kgdb.o
@@ -94,12 +94,13 @@ obj-$(CONFIG_OLPC)          += olpc.o
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
-        obj-y                          += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o
+        obj-y                          += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o
         obj-$(CONFIG_X86_PM_TIMER)     += pmtimer_64.o
         obj-$(CONFIG_AUDIT)            += audit_64.o
 
         obj-$(CONFIG_GART_IOMMU)       += pci-gart_64.o aperture_64.o
         obj-$(CONFIG_CALGARY_IOMMU)    += pci-calgary_64.o tce_64.o
+        obj-$(CONFIG_AMD_IOMMU)                += amd_iommu_init.o amd_iommu.o
         obj-$(CONFIG_SWIOTLB)          += pci-swiotlb_64.o
 
         obj-$(CONFIG_PCI_MMCONFIG)     += mmconf-fam10h_64.o
index 33c5216fd3e1f5137b0b8c52fa8178ac328d630a..f489d7a9be92ffd00c662c4b18554637e4311406 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/pgtable.h>
 #include <asm/io_apic.h>
 #include <asm/apic.h>
+#include <asm/genapic.h>
 #include <asm/io.h>
 #include <asm/mpspec.h>
 #include <asm/smp.h>
@@ -106,21 +107,6 @@ static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
  */
 enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
 
-#ifdef CONFIG_X86_64
-
-/* rely on all ACPI tables being in the direct mapping */
-char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
-{
-       if (!phys_addr || !size)
-               return NULL;
-
-       if (phys_addr+size <= (max_pfn_mapped << PAGE_SHIFT) + PAGE_SIZE)
-               return __va(phys_addr);
-
-       return NULL;
-}
-
-#else
 
 /*
  * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
@@ -139,11 +125,15 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size)
        unsigned long base, offset, mapped_size;
        int idx;
 
-       if (phys + size < 8 * 1024 * 1024)
+       if (!phys || !size)
+               return NULL;
+
+       if (phys+size <= (max_low_pfn_mapped << PAGE_SHIFT))
                return __va(phys);
 
        offset = phys & (PAGE_SIZE - 1);
        mapped_size = PAGE_SIZE - offset;
+       clear_fixmap(FIX_ACPI_END);
        set_fixmap(FIX_ACPI_END, phys);
        base = fix_to_virt(FIX_ACPI_END);
 
@@ -155,13 +145,13 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size)
                if (--idx < FIX_ACPI_BEGIN)
                        return NULL;    /* cannot handle this */
                phys += PAGE_SIZE;
+               clear_fixmap(idx);
                set_fixmap(idx, phys);
                mapped_size += PAGE_SIZE;
        }
 
        return ((unsigned char *)base + offset);
 }
-#endif
 
 #ifdef CONFIG_PCI_MMCONFIG
 /* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
@@ -338,8 +328,6 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e
 
 #ifdef CONFIG_X86_IO_APIC
 
-struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];
-
 static int __init
 acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
 {
@@ -514,8 +502,6 @@ 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) {
-               extern void eisa_set_level_irq(unsigned int irq);
-
                if (triggering == ACPI_LEVEL_SENSITIVE)
                        eisa_set_level_irq(gsi);
        }
@@ -860,6 +846,364 @@ static int __init acpi_parse_madt_lapic_entries(void)
 #endif                         /* CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_IO_APIC
+#define MP_ISA_BUS             0
+
+#ifdef CONFIG_X86_ES7000
+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];
+
+static int mp_find_ioapic(int gsi)
+{
+       int i = 0;
+
+       /* Find the IOAPIC that manages this GSI. */
+       for (i = 0; i < nr_ioapics; i++) {
+               if ((gsi >= mp_ioapic_routing[i].gsi_base)
+                   && (gsi <= mp_ioapic_routing[i].gsi_end))
+                       return i;
+       }
+
+       printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
+       return -1;
+}
+
+static u8 __init uniq_ioapic_id(u8 id)
+{
+#ifdef CONFIG_X86_32
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+           !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
+               return io_apic_get_unique_id(nr_ioapics, id);
+       else
+               return id;
+#else
+       int i;
+       DECLARE_BITMAP(used, 256);
+       bitmap_zero(used, 256);
+       for (i = 0; i < nr_ioapics; i++) {
+               struct mp_config_ioapic *ia = &mp_ioapics[i];
+               __set_bit(ia->mp_apicid, used);
+       }
+       if (!test_bit(id, used))
+               return id;
+       return find_first_zero_bit(used, 256);
+#endif
+}
+
+static int bad_ioapic(unsigned long address)
+{
+       if (nr_ioapics >= MAX_IO_APICS) {
+               printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
+                      "(found %d)\n", MAX_IO_APICS, nr_ioapics);
+               panic("Recompile kernel with bigger MAX_IO_APICS!\n");
+       }
+       if (!address) {
+               printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
+                      " found in table, skipping!\n");
+               return 1;
+       }
+       return 0;
+}
+
+void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
+{
+       int idx = 0;
+
+       if (bad_ioapic(address))
+               return;
+
+       idx = nr_ioapics;
+
+       mp_ioapics[idx].mp_type = MP_IOAPIC;
+       mp_ioapics[idx].mp_flags = MPC_APIC_USABLE;
+       mp_ioapics[idx].mp_apicaddr = address;
+
+       set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
+       mp_ioapics[idx].mp_apicid = uniq_ioapic_id(id);
+#ifdef CONFIG_X86_32
+       mp_ioapics[idx].mp_apicver = io_apic_get_version(idx);
+#else
+       mp_ioapics[idx].mp_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].mp_apicid;
+       mp_ioapic_routing[idx].gsi_base = gsi_base;
+       mp_ioapic_routing[idx].gsi_end = gsi_base +
+           io_apic_get_redir_entries(idx);
+
+       printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, "
+              "GSI %d-%d\n", idx, mp_ioapics[idx].mp_apicid,
+              mp_ioapics[idx].mp_apicver, mp_ioapics[idx].mp_apicaddr,
+              mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end);
+
+       nr_ioapics++;
+}
+
+static void assign_to_mp_irq(struct mp_config_intsrc *m,
+                                   struct mp_config_intsrc *mp_irq)
+{
+       memcpy(mp_irq, m, sizeof(struct mp_config_intsrc));
+}
+
+static int mp_irq_cmp(struct mp_config_intsrc *mp_irq,
+                               struct mp_config_intsrc *m)
+{
+       return memcmp(mp_irq, m, sizeof(struct mp_config_intsrc));
+}
+
+static void save_mp_irq(struct mp_config_intsrc *m)
+{
+       int i;
+
+       for (i = 0; i < mp_irq_entries; i++) {
+               if (!mp_irq_cmp(&mp_irqs[i], m))
+                       return;
+       }
+
+       assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
+       if (++mp_irq_entries == MAX_IRQ_SOURCES)
+               panic("Max # of irq sources exceeded!!\n");
+}
+
+void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
+{
+       int ioapic;
+       int pin;
+       struct mp_config_intsrc mp_irq;
+
+       /*
+        * Convert 'gsi' to 'ioapic.pin'.
+        */
+       ioapic = mp_find_ioapic(gsi);
+       if (ioapic < 0)
+               return;
+       pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
+
+       /*
+        * TBD: This check is for faulty timer entries, where the override
+        *      erroneously sets the trigger to level, resulting in a HUGE
+        *      increase of timer interrupts!
+        */
+       if ((bus_irq == 0) && (trigger == 3))
+               trigger = 1;
+
+       mp_irq.mp_type = MP_INTSRC;
+       mp_irq.mp_irqtype = mp_INT;
+       mp_irq.mp_irqflag = (trigger << 2) | polarity;
+       mp_irq.mp_srcbus = MP_ISA_BUS;
+       mp_irq.mp_srcbusirq = bus_irq;  /* IRQ */
+       mp_irq.mp_dstapic = mp_ioapics[ioapic].mp_apicid; /* APIC ID */
+       mp_irq.mp_dstirq = pin; /* INTIN# */
+
+       save_mp_irq(&mp_irq);
+}
+
+void __init mp_config_acpi_legacy_irqs(void)
+{
+       int i;
+       int ioapic;
+       unsigned int dstapic;
+       struct mp_config_intsrc mp_irq;
+
+#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
+       /*
+        * Fabricate the legacy ISA bus (bus #31).
+        */
+       mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
+#endif
+       set_bit(MP_ISA_BUS, mp_bus_not_pci);
+       Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
+
+#ifdef CONFIG_X86_ES7000
+       /*
+        * Older generations of ES7000 have no legacy identity mappings
+        */
+       if (es7000_plat == 1)
+               return;
+#endif
+
+       /*
+        * Locate the IOAPIC that manages the ISA IRQs (0-15).
+        */
+       ioapic = mp_find_ioapic(0);
+       if (ioapic < 0)
+               return;
+       dstapic = mp_ioapics[ioapic].mp_apicid;
+
+       /*
+        * Use the default configuration for the IRQs 0-15.  Unless
+        * overridden by (MADT) interrupt source override entries.
+        */
+       for (i = 0; i < 16; i++) {
+               int idx;
+
+               for (idx = 0; idx < mp_irq_entries; idx++) {
+                       struct mp_config_intsrc *irq = mp_irqs + idx;
+
+                       /* Do we already have a mapping for this ISA IRQ? */
+                       if (irq->mp_srcbus == MP_ISA_BUS
+                           && irq->mp_srcbusirq == i)
+                               break;
+
+                       /* Do we already have a mapping for this IOAPIC pin */
+                       if (irq->mp_dstapic == dstapic &&
+                           irq->mp_dstirq == i)
+                               break;
+               }
+
+               if (idx != mp_irq_entries) {
+                       printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
+                       continue;       /* IRQ already used */
+               }
+
+               mp_irq.mp_type = MP_INTSRC;
+               mp_irq.mp_irqflag = 0;  /* Conforming */
+               mp_irq.mp_srcbus = MP_ISA_BUS;
+               mp_irq.mp_dstapic = dstapic;
+               mp_irq.mp_irqtype = mp_INT;
+               mp_irq.mp_srcbusirq = i; /* Identity mapped */
+               mp_irq.mp_dstirq = i;
+
+               save_mp_irq(&mp_irq);
+       }
+}
+
+int mp_register_gsi(u32 gsi, int triggering, int polarity)
+{
+       int ioapic;
+       int ioapic_pin;
+#ifdef CONFIG_X86_32
+#define MAX_GSI_NUM    4096
+#define IRQ_COMPRESSION_START  64
+
+       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_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)
+               return gsi;
+
+       ioapic = mp_find_ioapic(gsi);
+       if (ioapic < 0) {
+               printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+               return gsi;
+       }
+
+       ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
+
+#ifdef CONFIG_X86_32
+       if (ioapic_renumber_irq)
+               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,
+                      ioapic_pin);
+               return gsi;
+       }
+       if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) {
+               Dprintk(KERN_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 mp_config_intsrc mp_irq;
+       int ioapic;
+
+       if (!acpi_ioapic)
+               return 0;
+
+       /* print the entry should happen on mptable identically */
+       mp_irq.mp_type = MP_INTSRC;
+       mp_irq.mp_irqtype = mp_INT;
+       mp_irq.mp_irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
+                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
+       mp_irq.mp_srcbus = number;
+       mp_irq.mp_srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
+       ioapic = mp_find_ioapic(gsi);
+       mp_irq.mp_dstapic = mp_ioapic_routing[ioapic].apic_id;
+       mp_irq.mp_dstirq = gsi - mp_ioapic_routing[ioapic].gsi_base;
+
+       save_mp_irq(&mp_irq);
+#endif
+       return 0;
+}
+
 /*
  * Parse IOAPIC related entries in MADT
  * returns 0 on success, < 0 on error
@@ -1009,8 +1353,6 @@ static void __init acpi_process_madt(void)
        return;
 }
 
-#ifdef __i386__
-
 static int __init disable_acpi_irq(const struct dmi_system_id *d)
 {
        if (!acpi_force) {
@@ -1060,6 +1402,16 @@ static int __init force_acpi_ht(const struct dmi_system_id *d)
        return 0;
 }
 
+/*
+ * Force ignoring BIOS IRQ0 pin2 override
+ */
+static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
+{
+       pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
+       acpi_skip_timer_override = 1;
+       return 0;
+}
+
 /*
  * If your system is blacklisted here, but you find that acpi=force
  * works for you, please contact acpi-devel@sourceforge.net
@@ -1227,11 +1579,35 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
                     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
                     },
         },
+       /*
+        * HP laptops which use a DSDT reporting as HP/SB400/10000,
+        * which includes some code which overrides all temperature
+        * trip points to 16C if the INTIN2 input of the I/O APIC
+        * is enabled.  This input is incorrectly designated the
+        * ISA IRQ 0 via an interrupt source override even though
+        * it is wired to the output of the master 8259A and INTIN0
+        * is not connected at all.  Force ignoring BIOS IRQ0 pin2
+        * override in that cases.
+        */
+       {
+        .callback = dmi_ignore_irq0_timer_override,
+        .ident = "HP NX6125 laptop",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"),
+                    },
+        },
+       {
+        .callback = dmi_ignore_irq0_timer_override,
+        .ident = "HP NX6325 laptop",
+        .matches = {
+                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                    DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
+                    },
+        },
        {}
 };
 
-#endif                         /* __i386__ */
-
 /*
  * acpi_boot_table_init() and acpi_boot_init()
  *  called from setup_arch(), always.
@@ -1259,9 +1635,7 @@ int __init acpi_boot_table_init(void)
 {
        int error;
 
-#ifdef __i386__
        dmi_check_system(acpi_dmi_table);
-#endif
 
        /*
         * If acpi_disabled, bail out
@@ -1386,6 +1760,20 @@ static int __init parse_pci(char *arg)
 }
 early_param("pci", parse_pci);
 
+int __init acpi_mps_check(void)
+{
+#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_X86_MPPARSE)
+/* mptable code is not built-in*/
+       if (acpi_disabled || acpi_noirq) {
+               printk(KERN_WARNING "MPS support code is not built-in.\n"
+                      "Using acpi=off or acpi=noirq or pci=noacpi "
+                      "may have problem\n");
+               return 1;
+       }
+#endif
+       return 0;
+}
+
 #ifdef CONFIG_X86_IO_APIC
 static int __init parse_acpi_skip_timer_override(char *arg)
 {
index 36af01f029eddbfe7b2bdc05a0f2b59ab5c3666a..e6a4b564ccaa0e1ecb2669c77978ff7d85d79829 100644 (file)
@@ -86,7 +86,9 @@ int acpi_save_state_mem(void)
        saved_magic = 0x12345678;
 #else /* CONFIG_64BIT */
        header->trampoline_segment = setup_trampoline() >> 4;
-       init_rsp = (unsigned long)temp_stack + 4096;
+#ifdef CONFIG_SMP
+       stack_start.sp = temp_stack + 4096;
+#endif
        initial_code = (unsigned long)wakeup_long64;
        saved_magic = 0x123456789abcdef0;
 #endif /* CONFIG_64BIT */
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
new file mode 100644 (file)
index 0000000..f2766d8
--- /dev/null
@@ -0,0 +1,962 @@
+/*
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
+ * Author: Joerg Roedel <joerg.roedel@amd.com>
+ *         Leo Duran <leo.duran@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/pci.h>
+#include <linux/gfp.h>
+#include <linux/bitops.h>
+#include <linux/scatterlist.h>
+#include <linux/iommu-helper.h>
+#include <asm/proto.h>
+#include <asm/gart.h>
+#include <asm/amd_iommu_types.h>
+#include <asm/amd_iommu.h>
+
+#define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
+
+#define to_pages(addr, size) \
+        (round_up(((addr) & ~PAGE_MASK) + (size), PAGE_SIZE) >> PAGE_SHIFT)
+
+static DEFINE_RWLOCK(amd_iommu_devtable_lock);
+
+struct command {
+       u32 data[4];
+};
+
+static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
+                            struct unity_map_entry *e);
+
+static int iommu_has_npcache(struct amd_iommu *iommu)
+{
+       return iommu->cap & IOMMU_CAP_NPCACHE;
+}
+
+static int __iommu_queue_command(struct amd_iommu *iommu, struct command *cmd)
+{
+       u32 tail, head;
+       u8 *target;
+
+       tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+       target = (iommu->cmd_buf + tail);
+       memcpy_toio(target, cmd, sizeof(*cmd));
+       tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
+       head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
+       if (tail == head)
+               return -ENOMEM;
+       writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+
+       return 0;
+}
+
+static int iommu_queue_command(struct amd_iommu *iommu, struct command *cmd)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       ret = __iommu_queue_command(iommu, cmd);
+       spin_unlock_irqrestore(&iommu->lock, flags);
+
+       return ret;
+}
+
+static int iommu_completion_wait(struct amd_iommu *iommu)
+{
+       int ret;
+       struct command cmd;
+       volatile u64 ready = 0;
+       unsigned long ready_phys = virt_to_phys(&ready);
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.data[0] = LOW_U32(ready_phys) | CMD_COMPL_WAIT_STORE_MASK;
+       cmd.data[1] = HIGH_U32(ready_phys);
+       cmd.data[2] = 1; /* value written to 'ready' */
+       CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT);
+
+       iommu->need_sync = 0;
+
+       ret = iommu_queue_command(iommu, &cmd);
+
+       if (ret)
+               return ret;
+
+       while (!ready)
+               cpu_relax();
+
+       return 0;
+}
+
+static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid)
+{
+       struct command cmd;
+
+       BUG_ON(iommu == NULL);
+
+       memset(&cmd, 0, sizeof(cmd));
+       CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY);
+       cmd.data[0] = devid;
+
+       iommu->need_sync = 1;
+
+       return iommu_queue_command(iommu, &cmd);
+}
+
+static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
+               u64 address, u16 domid, int pde, int s)
+{
+       struct command cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       address &= PAGE_MASK;
+       CMD_SET_TYPE(&cmd, CMD_INV_IOMMU_PAGES);
+       cmd.data[1] |= domid;
+       cmd.data[2] = LOW_U32(address);
+       cmd.data[3] = HIGH_U32(address);
+       if (s)
+               cmd.data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
+       if (pde)
+               cmd.data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
+
+       iommu->need_sync = 1;
+
+       return iommu_queue_command(iommu, &cmd);
+}
+
+static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid,
+               u64 address, size_t size)
+{
+       int s = 0;
+       unsigned pages = to_pages(address, size);
+
+       address &= PAGE_MASK;
+
+       if (pages > 1) {
+               /*
+                * If we have to flush more than one page, flush all
+                * TLB entries for this domain
+                */
+               address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+               s = 1;
+       }
+
+       iommu_queue_inv_iommu_pages(iommu, address, domid, 0, s);
+
+       return 0;
+}
+
+static int iommu_map(struct protection_domain *dom,
+                    unsigned long bus_addr,
+                    unsigned long phys_addr,
+                    int prot)
+{
+       u64 __pte, *pte, *page;
+
+       bus_addr  = PAGE_ALIGN(bus_addr);
+       phys_addr = PAGE_ALIGN(bus_addr);
+
+       /* only support 512GB address spaces for now */
+       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)];
+
+       if (IOMMU_PTE_PRESENT(*pte))
+               return -EBUSY;
+
+       __pte = phys_addr | IOMMU_PTE_P;
+       if (prot & IOMMU_PROT_IR)
+               __pte |= IOMMU_PTE_IR;
+       if (prot & IOMMU_PROT_IW)
+               __pte |= IOMMU_PTE_IW;
+
+       *pte = __pte;
+
+       return 0;
+}
+
+static int iommu_for_unity_map(struct amd_iommu *iommu,
+                              struct unity_map_entry *entry)
+{
+       u16 bdf, i;
+
+       for (i = entry->devid_start; i <= entry->devid_end; ++i) {
+               bdf = amd_iommu_alias_table[i];
+               if (amd_iommu_rlookup_table[bdf] == iommu)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int iommu_init_unity_mappings(struct amd_iommu *iommu)
+{
+       struct unity_map_entry *entry;
+       int ret;
+
+       list_for_each_entry(entry, &amd_iommu_unity_map, list) {
+               if (!iommu_for_unity_map(iommu, entry))
+                       continue;
+               ret = dma_ops_unity_map(iommu->default_dom, entry);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
+                            struct unity_map_entry *e)
+{
+       u64 addr;
+       int ret;
+
+       for (addr = e->address_start; addr < e->address_end;
+            addr += PAGE_SIZE) {
+               ret = iommu_map(&dma_dom->domain, addr, addr, e->prot);
+               if (ret)
+                       return ret;
+               /*
+                * if unity mapping is in aperture range mark the page
+                * as allocated in the aperture
+                */
+               if (addr < dma_dom->aperture_size)
+                       __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap);
+       }
+
+       return 0;
+}
+
+static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom,
+                                         u16 devid)
+{
+       struct unity_map_entry *e;
+       int ret;
+
+       list_for_each_entry(e, &amd_iommu_unity_map, list) {
+               if (!(devid >= e->devid_start && devid <= e->devid_end))
+                       continue;
+               ret = dma_ops_unity_map(dma_dom, e);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static unsigned long dma_mask_to_pages(unsigned long mask)
+{
+       return (mask >> PAGE_SHIFT) +
+               (PAGE_ALIGN(mask & ~PAGE_MASK) >> PAGE_SHIFT);
+}
+
+static unsigned long dma_ops_alloc_addresses(struct device *dev,
+                                            struct dma_ops_domain *dom,
+                                            unsigned int pages)
+{
+       unsigned long limit = dma_mask_to_pages(*dev->dma_mask);
+       unsigned long address;
+       unsigned long size = dom->aperture_size >> PAGE_SHIFT;
+       unsigned long boundary_size;
+
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                       PAGE_SIZE) >> PAGE_SHIFT;
+       limit = limit < size ? limit : size;
+
+       if (dom->next_bit >= limit)
+               dom->next_bit = 0;
+
+       address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
+                       0 , boundary_size, 0);
+       if (address == -1)
+               address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
+                               0, boundary_size, 0);
+
+       if (likely(address != -1)) {
+               dom->next_bit = address + pages;
+               address <<= PAGE_SHIFT;
+       } else
+               address = bad_dma_address;
+
+       WARN_ON((address + (PAGE_SIZE*pages)) > dom->aperture_size);
+
+       return address;
+}
+
+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);
+}
+
+static u16 domain_id_alloc(void)
+{
+       unsigned long flags;
+       int id;
+
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       id = find_first_zero_bit(amd_iommu_pd_alloc_bitmap, MAX_DOMAIN_ID);
+       BUG_ON(id == 0);
+       if (id > 0 && id < MAX_DOMAIN_ID)
+               __set_bit(id, amd_iommu_pd_alloc_bitmap);
+       else
+               id = 0;
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       return id;
+}
+
+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;
+
+       if (start_page + pages > last_page)
+               pages = last_page - start_page;
+
+       set_bit_string(dom->bitmap, start_page, pages);
+}
+
+static void dma_ops_free_pagetable(struct dma_ops_domain *dma_dom)
+{
+       int i, j;
+       u64 *p1, *p2, *p3;
+
+       p1 = dma_dom->domain.pt_root;
+
+       if (!p1)
+               return;
+
+       for (i = 0; i < 512; ++i) {
+               if (!IOMMU_PTE_PRESENT(p1[i]))
+                       continue;
+
+               p2 = IOMMU_PTE_PAGE(p1[i]);
+               for (j = 0; j < 512; ++i) {
+                       if (!IOMMU_PTE_PRESENT(p2[j]))
+                               continue;
+                       p3 = IOMMU_PTE_PAGE(p2[j]);
+                       free_page((unsigned long)p3);
+               }
+
+               free_page((unsigned long)p2);
+       }
+
+       free_page((unsigned long)p1);
+}
+
+static void dma_ops_domain_free(struct dma_ops_domain *dom)
+{
+       if (!dom)
+               return;
+
+       dma_ops_free_pagetable(dom);
+
+       kfree(dom->pte_pages);
+
+       kfree(dom->bitmap);
+
+       kfree(dom);
+}
+
+static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
+                                                  unsigned order)
+{
+       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)
+               return NULL;
+
+       spin_lock_init(&dma_dom->domain.lock);
+
+       dma_dom->domain.id = domain_id_alloc();
+       if (dma_dom->domain.id == 0)
+               goto free_dma_dom;
+       dma_dom->domain.mode = PAGE_MODE_3_LEVEL;
+       dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL);
+       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;
+
+       if (iommu->exclusion_start &&
+           iommu->exclusion_start < dma_dom->aperture_size) {
+               unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
+               int pages = to_pages(iommu->exclusion_start,
+                               iommu->exclusion_length);
+               dma_ops_reserve_addresses(dma_dom, startpage, pages);
+       }
+
+       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->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;
+
+free_dma_dom:
+       dma_ops_domain_free(dma_dom);
+
+       return NULL;
+}
+
+static struct protection_domain *domain_for_device(u16 devid)
+{
+       struct protection_domain *dom;
+       unsigned long flags;
+
+       read_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       dom = amd_iommu_pd_table[devid];
+       read_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       return dom;
+}
+
+static void set_device_domain(struct amd_iommu *iommu,
+                             struct protection_domain *domain,
+                             u16 devid)
+{
+       unsigned long flags;
+
+       u64 pte_root = virt_to_phys(domain->pt_root);
+
+       pte_root |= (domain->mode & 0x07) << 9;
+       pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | 2;
+
+       write_lock_irqsave(&amd_iommu_devtable_lock, flags);
+       amd_iommu_dev_table[devid].data[0] = pte_root;
+       amd_iommu_dev_table[devid].data[1] = pte_root >> 32;
+       amd_iommu_dev_table[devid].data[2] = domain->id;
+
+       amd_iommu_pd_table[devid] = domain;
+       write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+       iommu_queue_inv_dev_entry(iommu, devid);
+
+       iommu->need_sync = 1;
+}
+
+static int get_device_resources(struct device *dev,
+                               struct amd_iommu **iommu,
+                               struct protection_domain **domain,
+                               u16 *bdf)
+{
+       struct dma_ops_domain *dma_dom;
+       struct pci_dev *pcidev;
+       u16 _bdf;
+
+       BUG_ON(!dev || dev->bus != &pci_bus_type || !dev->dma_mask);
+
+       pcidev = to_pci_dev(dev);
+       _bdf = (pcidev->bus->number << 8) | pcidev->devfn;
+
+       if (_bdf >= amd_iommu_last_bdf) {
+               *iommu = NULL;
+               *domain = NULL;
+               *bdf = 0xffff;
+               return 0;
+       }
+
+       *bdf = amd_iommu_alias_table[_bdf];
+
+       *iommu = amd_iommu_rlookup_table[*bdf];
+       if (*iommu == NULL)
+               return 0;
+       dma_dom = (*iommu)->default_dom;
+       *domain = domain_for_device(*bdf);
+       if (*domain == NULL) {
+               *domain = &dma_dom->domain;
+               set_device_domain(*iommu, *domain, *bdf);
+               printk(KERN_INFO "AMD IOMMU: Using protection domain %d for "
+                               "device ", (*domain)->id);
+               print_devid(_bdf, 1);
+       }
+
+       return 1;
+}
+
+static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
+                                    struct dma_ops_domain *dom,
+                                    unsigned long address,
+                                    phys_addr_t paddr,
+                                    int direction)
+{
+       u64 *pte, __pte;
+
+       WARN_ON(address > dom->aperture_size);
+
+       paddr &= PAGE_MASK;
+
+       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+       pte += IOMMU_PTE_L0_INDEX(address);
+
+       __pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
+
+       if (direction == DMA_TO_DEVICE)
+               __pte |= IOMMU_PTE_IR;
+       else if (direction == DMA_FROM_DEVICE)
+               __pte |= IOMMU_PTE_IW;
+       else if (direction == DMA_BIDIRECTIONAL)
+               __pte |= IOMMU_PTE_IR | IOMMU_PTE_IW;
+
+       WARN_ON(*pte);
+
+       *pte = __pte;
+
+       return (dma_addr_t)address;
+}
+
+static void dma_ops_domain_unmap(struct amd_iommu *iommu,
+                                struct dma_ops_domain *dom,
+                                unsigned long address)
+{
+       u64 *pte;
+
+       if (address >= dom->aperture_size)
+               return;
+
+       WARN_ON(address & 0xfffULL || address > dom->aperture_size);
+
+       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+       pte += IOMMU_PTE_L0_INDEX(address);
+
+       WARN_ON(!*pte);
+
+       *pte = 0ULL;
+}
+
+static dma_addr_t __map_single(struct device *dev,
+                              struct amd_iommu *iommu,
+                              struct dma_ops_domain *dma_dom,
+                              phys_addr_t paddr,
+                              size_t size,
+                              int dir)
+{
+       dma_addr_t offset = paddr & ~PAGE_MASK;
+       dma_addr_t address, start;
+       unsigned int pages;
+       int i;
+
+       pages = to_pages(paddr, size);
+       paddr &= PAGE_MASK;
+
+       address = dma_ops_alloc_addresses(dev, dma_dom, pages);
+       if (unlikely(address == bad_dma_address))
+               goto out;
+
+       start = address;
+       for (i = 0; i < pages; ++i) {
+               dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               paddr += PAGE_SIZE;
+               start += PAGE_SIZE;
+       }
+       address += offset;
+
+out:
+       return address;
+}
+
+static void __unmap_single(struct amd_iommu *iommu,
+                          struct dma_ops_domain *dma_dom,
+                          dma_addr_t dma_addr,
+                          size_t size,
+                          int dir)
+{
+       dma_addr_t i, start;
+       unsigned int pages;
+
+       if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size))
+               return;
+
+       pages = to_pages(dma_addr, size);
+       dma_addr &= PAGE_MASK;
+       start = dma_addr;
+
+       for (i = 0; i < pages; ++i) {
+               dma_ops_domain_unmap(iommu, dma_dom, start);
+               start += PAGE_SIZE;
+       }
+
+       dma_ops_free_addresses(dma_dom, dma_addr, pages);
+}
+
+static dma_addr_t map_single(struct device *dev, phys_addr_t paddr,
+                            size_t size, int dir)
+{
+       unsigned long flags;
+       struct amd_iommu *iommu;
+       struct protection_domain *domain;
+       u16 devid;
+       dma_addr_t addr;
+
+       get_device_resources(dev, &iommu, &domain, &devid);
+
+       if (iommu == NULL || domain == NULL)
+               return (dma_addr_t)paddr;
+
+       spin_lock_irqsave(&domain->lock, flags);
+       addr = __map_single(dev, iommu, domain->priv, paddr, size, dir);
+       if (addr == bad_dma_address)
+               goto out;
+
+       if (iommu_has_npcache(iommu))
+               iommu_flush_pages(iommu, domain->id, addr, size);
+
+       if (iommu->need_sync)
+               iommu_completion_wait(iommu);
+
+out:
+       spin_unlock_irqrestore(&domain->lock, flags);
+
+       return addr;
+}
+
+static void unmap_single(struct device *dev, dma_addr_t dma_addr,
+                        size_t size, int dir)
+{
+       unsigned long flags;
+       struct amd_iommu *iommu;
+       struct protection_domain *domain;
+       u16 devid;
+
+       if (!get_device_resources(dev, &iommu, &domain, &devid))
+               return;
+
+       spin_lock_irqsave(&domain->lock, flags);
+
+       __unmap_single(iommu, domain->priv, dma_addr, size, dir);
+
+       iommu_flush_pages(iommu, domain->id, dma_addr, size);
+
+       if (iommu->need_sync)
+               iommu_completion_wait(iommu);
+
+       spin_unlock_irqrestore(&domain->lock, flags);
+}
+
+static int map_sg_no_iommu(struct device *dev, struct scatterlist *sglist,
+                          int nelems, int dir)
+{
+       struct scatterlist *s;
+       int i;
+
+       for_each_sg(sglist, s, nelems, i) {
+               s->dma_address = (dma_addr_t)sg_phys(s);
+               s->dma_length  = s->length;
+       }
+
+       return nelems;
+}
+
+static int map_sg(struct device *dev, struct scatterlist *sglist,
+                 int nelems, int dir)
+{
+       unsigned long flags;
+       struct amd_iommu *iommu;
+       struct protection_domain *domain;
+       u16 devid;
+       int i;
+       struct scatterlist *s;
+       phys_addr_t paddr;
+       int mapped_elems = 0;
+
+       get_device_resources(dev, &iommu, &domain, &devid);
+
+       if (!iommu || !domain)
+               return map_sg_no_iommu(dev, sglist, nelems, dir);
+
+       spin_lock_irqsave(&domain->lock, flags);
+
+       for_each_sg(sglist, s, nelems, i) {
+               paddr = sg_phys(s);
+
+               s->dma_address = __map_single(dev, iommu, domain->priv,
+                                             paddr, s->length, dir);
+
+               if (s->dma_address) {
+                       s->dma_length = s->length;
+                       mapped_elems++;
+               } else
+                       goto unmap;
+               if (iommu_has_npcache(iommu))
+                       iommu_flush_pages(iommu, domain->id, s->dma_address,
+                                         s->dma_length);
+       }
+
+       if (iommu->need_sync)
+               iommu_completion_wait(iommu);
+
+out:
+       spin_unlock_irqrestore(&domain->lock, flags);
+
+       return mapped_elems;
+unmap:
+       for_each_sg(sglist, s, mapped_elems, i) {
+               if (s->dma_address)
+                       __unmap_single(iommu, domain->priv, s->dma_address,
+                                      s->dma_length, dir);
+               s->dma_address = s->dma_length = 0;
+       }
+
+       mapped_elems = 0;
+
+       goto out;
+}
+
+static void unmap_sg(struct device *dev, struct scatterlist *sglist,
+                    int nelems, int dir)
+{
+       unsigned long flags;
+       struct amd_iommu *iommu;
+       struct protection_domain *domain;
+       struct scatterlist *s;
+       u16 devid;
+       int i;
+
+       if (!get_device_resources(dev, &iommu, &domain, &devid))
+               return;
+
+       spin_lock_irqsave(&domain->lock, flags);
+
+       for_each_sg(sglist, s, nelems, i) {
+               __unmap_single(iommu, domain->priv, s->dma_address,
+                              s->dma_length, dir);
+               iommu_flush_pages(iommu, domain->id, s->dma_address,
+                                 s->dma_length);
+               s->dma_address = s->dma_length = 0;
+       }
+
+       if (iommu->need_sync)
+               iommu_completion_wait(iommu);
+
+       spin_unlock_irqrestore(&domain->lock, flags);
+}
+
+static void *alloc_coherent(struct device *dev, size_t size,
+                           dma_addr_t *dma_addr, gfp_t flag)
+{
+       unsigned long flags;
+       void *virt_addr;
+       struct amd_iommu *iommu;
+       struct protection_domain *domain;
+       u16 devid;
+       phys_addr_t paddr;
+
+       virt_addr = (void *)__get_free_pages(flag, get_order(size));
+       if (!virt_addr)
+               return 0;
+
+       memset(virt_addr, 0, size);
+       paddr = virt_to_phys(virt_addr);
+
+       get_device_resources(dev, &iommu, &domain, &devid);
+
+       if (!iommu || !domain) {
+               *dma_addr = (dma_addr_t)paddr;
+               return virt_addr;
+       }
+
+       spin_lock_irqsave(&domain->lock, flags);
+
+       *dma_addr = __map_single(dev, iommu, domain->priv, paddr,
+                                size, DMA_BIDIRECTIONAL);
+
+       if (*dma_addr == bad_dma_address) {
+               free_pages((unsigned long)virt_addr, get_order(size));
+               virt_addr = NULL;
+               goto out;
+       }
+
+       if (iommu_has_npcache(iommu))
+               iommu_flush_pages(iommu, domain->id, *dma_addr, size);
+
+       if (iommu->need_sync)
+               iommu_completion_wait(iommu);
+
+out:
+       spin_unlock_irqrestore(&domain->lock, flags);
+
+       return virt_addr;
+}
+
+static void free_coherent(struct device *dev, size_t size,
+                         void *virt_addr, dma_addr_t dma_addr)
+{
+       unsigned long flags;
+       struct amd_iommu *iommu;
+       struct protection_domain *domain;
+       u16 devid;
+
+       get_device_resources(dev, &iommu, &domain, &devid);
+
+       if (!iommu || !domain)
+               goto free_mem;
+
+       spin_lock_irqsave(&domain->lock, flags);
+
+       __unmap_single(iommu, domain->priv, dma_addr, size, DMA_BIDIRECTIONAL);
+       iommu_flush_pages(iommu, domain->id, dma_addr, size);
+
+       if (iommu->need_sync)
+               iommu_completion_wait(iommu);
+
+       spin_unlock_irqrestore(&domain->lock, flags);
+
+free_mem:
+       free_pages((unsigned long)virt_addr, get_order(size));
+}
+
+/*
+ * If the driver core informs the DMA layer if a driver grabs a device
+ * we don't need to preallocate the protection domains anymore.
+ * For now we have to.
+ */
+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) {
+               devid = (dev->bus->number << 8) | dev->devfn;
+               if (devid >= amd_iommu_last_bdf)
+                       continue;
+               devid = amd_iommu_alias_table[devid];
+               if (domain_for_device(devid))
+                       continue;
+               iommu = amd_iommu_rlookup_table[devid];
+               if (!iommu)
+                       continue;
+               dma_dom = dma_ops_domain_alloc(iommu, order);
+               if (!dma_dom)
+                       continue;
+               init_unity_mappings_for_device(dma_dom, devid);
+               set_device_domain(iommu, &dma_dom->domain, devid);
+               printk(KERN_INFO "AMD IOMMU: Allocated domain %d for device ",
+                      dma_dom->domain.id);
+               print_devid(devid, 1);
+       }
+}
+
+static struct dma_mapping_ops amd_iommu_dma_ops = {
+       .alloc_coherent = alloc_coherent,
+       .free_coherent = free_coherent,
+       .map_single = map_single,
+       .unmap_single = unmap_single,
+       .map_sg = map_sg,
+       .unmap_sg = unmap_sg,
+};
+
+int __init amd_iommu_init_dma_ops(void)
+{
+       struct amd_iommu *iommu;
+       int order = amd_iommu_aperture_order;
+       int ret;
+
+       list_for_each_entry(iommu, &amd_iommu_list, list) {
+               iommu->default_dom = dma_ops_domain_alloc(iommu, order);
+               if (iommu->default_dom == NULL)
+                       return -ENOMEM;
+               ret = iommu_init_unity_mappings(iommu);
+               if (ret)
+                       goto free_domains;
+       }
+
+       if (amd_iommu_isolate)
+               prealloc_protection_domains();
+
+       iommu_detected = 1;
+       force_iommu = 1;
+       bad_dma_address = 0;
+#ifdef CONFIG_GART_IOMMU
+       gart_iommu_aperture_disabled = 1;
+       gart_iommu_aperture = 0;
+#endif
+
+       dma_ops = &amd_iommu_dma_ops;
+
+       return 0;
+
+free_domains:
+
+       list_for_each_entry(iommu, &amd_iommu_list, list) {
+               if (iommu->default_dom)
+                       dma_ops_domain_free(iommu->default_dom);
+       }
+
+       return ret;
+}
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
new file mode 100644 (file)
index 0000000..2a13e43
--- /dev/null
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
+ * Author: Joerg Roedel <joerg.roedel@amd.com>
+ *         Leo Duran <leo.duran@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/gfp.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <asm/pci-direct.h>
+#include <asm/amd_iommu_types.h>
+#include <asm/amd_iommu.h>
+#include <asm/gart.h>
+
+/*
+ * definitions for the ACPI scanning code
+ */
+#define UPDATE_LAST_BDF(x) do {\
+       if ((x) > amd_iommu_last_bdf) \
+               amd_iommu_last_bdf = (x); \
+       } while (0);
+
+#define DEVID(bus, devfn) (((bus) << 8) | (devfn))
+#define PCI_BUS(x) (((x) >> 8) & 0xff)
+#define IVRS_HEADER_LENGTH 48
+#define TBL_SIZE(x) (1 << (PAGE_SHIFT + get_order(amd_iommu_last_bdf * (x))))
+
+#define ACPI_IVHD_TYPE                  0x10
+#define ACPI_IVMD_TYPE_ALL              0x20
+#define ACPI_IVMD_TYPE                  0x21
+#define ACPI_IVMD_TYPE_RANGE            0x22
+
+#define IVHD_DEV_ALL                    0x01
+#define IVHD_DEV_SELECT                 0x02
+#define IVHD_DEV_SELECT_RANGE_START     0x03
+#define IVHD_DEV_RANGE_END              0x04
+#define IVHD_DEV_ALIAS                  0x42
+#define IVHD_DEV_ALIAS_RANGE            0x43
+#define IVHD_DEV_EXT_SELECT             0x46
+#define IVHD_DEV_EXT_SELECT_RANGE       0x47
+
+#define IVHD_FLAG_HT_TUN_EN             0x00
+#define IVHD_FLAG_PASSPW_EN             0x01
+#define IVHD_FLAG_RESPASSPW_EN          0x02
+#define IVHD_FLAG_ISOC_EN               0x03
+
+#define IVMD_FLAG_EXCL_RANGE            0x08
+#define IVMD_FLAG_UNITY_MAP             0x01
+
+#define ACPI_DEVFLAG_INITPASS           0x01
+#define ACPI_DEVFLAG_EXTINT             0x02
+#define ACPI_DEVFLAG_NMI                0x04
+#define ACPI_DEVFLAG_SYSMGT1            0x10
+#define ACPI_DEVFLAG_SYSMGT2            0x20
+#define ACPI_DEVFLAG_LINT0              0x40
+#define ACPI_DEVFLAG_LINT1              0x80
+#define ACPI_DEVFLAG_ATSDIS             0x10000000
+
+struct ivhd_header {
+       u8 type;
+       u8 flags;
+       u16 length;
+       u16 devid;
+       u16 cap_ptr;
+       u64 mmio_phys;
+       u16 pci_seg;
+       u16 info;
+       u32 reserved;
+} __attribute__((packed));
+
+struct ivhd_entry {
+       u8 type;
+       u16 devid;
+       u8 flags;
+       u32 ext;
+} __attribute__((packed));
+
+struct ivmd_header {
+       u8 type;
+       u8 flags;
+       u16 length;
+       u16 devid;
+       u16 aux;
+       u64 resv;
+       u64 range_start;
+       u64 range_length;
+} __attribute__((packed));
+
+static int __initdata amd_iommu_detected;
+
+u16 amd_iommu_last_bdf;
+struct list_head amd_iommu_unity_map;
+unsigned amd_iommu_aperture_order = 26;
+int amd_iommu_isolate;
+
+struct list_head amd_iommu_list;
+struct dev_table_entry *amd_iommu_dev_table;
+u16 *amd_iommu_alias_table;
+struct amd_iommu **amd_iommu_rlookup_table;
+struct protection_domain **amd_iommu_pd_table;
+unsigned long *amd_iommu_pd_alloc_bitmap;
+
+static u32 dev_table_size;
+static u32 alias_table_size;
+static u32 rlookup_table_size;
+
+static void __init iommu_set_exclusion_range(struct amd_iommu *iommu)
+{
+       u64 start = iommu->exclusion_start & PAGE_MASK;
+       u64 limit = (start + iommu->exclusion_length) & PAGE_MASK;
+       u64 entry;
+
+       if (!iommu->exclusion_start)
+               return;
+
+       entry = start | MMIO_EXCL_ENABLE_MASK;
+       memcpy_toio(iommu->mmio_base + MMIO_EXCL_BASE_OFFSET,
+                       &entry, sizeof(entry));
+
+       entry = limit;
+       memcpy_toio(iommu->mmio_base + MMIO_EXCL_LIMIT_OFFSET,
+                       &entry, sizeof(entry));
+}
+
+static void __init iommu_set_device_table(struct amd_iommu *iommu)
+{
+       u32 entry;
+
+       BUG_ON(iommu->mmio_base == NULL);
+
+       entry = virt_to_phys(amd_iommu_dev_table);
+       entry |= (dev_table_size >> 12) - 1;
+       memcpy_toio(iommu->mmio_base + MMIO_DEV_TABLE_OFFSET,
+                       &entry, sizeof(entry));
+}
+
+static void __init iommu_feature_enable(struct amd_iommu *iommu, u8 bit)
+{
+       u32 ctrl;
+
+       ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
+       ctrl |= (1 << bit);
+       writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
+}
+
+static void __init iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
+{
+       u32 ctrl;
+
+       ctrl = (u64)readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
+       ctrl &= ~(1 << bit);
+       writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET);
+}
+
+void __init iommu_enable(struct amd_iommu *iommu)
+{
+       printk(KERN_INFO "AMD IOMMU: Enabling IOMMU at ");
+       print_devid(iommu->devid, 0);
+       printk(" cap 0x%hx\n", iommu->cap_ptr);
+
+       iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
+}
+
+static u8 * __init iommu_map_mmio_space(u64 address)
+{
+       u8 *ret;
+
+       if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu"))
+               return NULL;
+
+       ret = ioremap_nocache(address, MMIO_REGION_LENGTH);
+       if (ret != NULL)
+               return ret;
+
+       release_mem_region(address, MMIO_REGION_LENGTH);
+
+       return NULL;
+}
+
+static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
+{
+       if (iommu->mmio_base)
+               iounmap(iommu->mmio_base);
+       release_mem_region(iommu->mmio_phys, MMIO_REGION_LENGTH);
+}
+
+static int __init find_last_devid_on_pci(int bus, int dev, int fn, int cap_ptr)
+{
+       u32 cap;
+
+       cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET);
+       UPDATE_LAST_BDF(DEVID(MMIO_GET_BUS(cap), MMIO_GET_LD(cap)));
+
+       return 0;
+}
+
+static int __init find_last_devid_from_ivhd(struct ivhd_header *h)
+{
+       u8 *p = (void *)h, *end = (void *)h;
+       struct ivhd_entry *dev;
+
+       p += sizeof(*h);
+       end += h->length;
+
+       find_last_devid_on_pci(PCI_BUS(h->devid),
+                       PCI_SLOT(h->devid),
+                       PCI_FUNC(h->devid),
+                       h->cap_ptr);
+
+       while (p < end) {
+               dev = (struct ivhd_entry *)p;
+               switch (dev->type) {
+               case IVHD_DEV_SELECT:
+               case IVHD_DEV_RANGE_END:
+               case IVHD_DEV_ALIAS:
+               case IVHD_DEV_EXT_SELECT:
+                       UPDATE_LAST_BDF(dev->devid);
+                       break;
+               default:
+                       break;
+               }
+               p += 0x04 << (*p >> 6);
+       }
+
+       WARN_ON(p != end);
+
+       return 0;
+}
+
+static int __init find_last_devid_acpi(struct acpi_table_header *table)
+{
+       int i;
+       u8 checksum = 0, *p = (u8 *)table, *end = (u8 *)table;
+       struct ivhd_header *h;
+
+       /*
+        * Validate checksum here so we don't need to do it when
+        * we actually parse the table
+        */
+       for (i = 0; i < table->length; ++i)
+               checksum += p[i];
+       if (checksum != 0)
+               /* ACPI table corrupt */
+               return -ENODEV;
+
+       p += IVRS_HEADER_LENGTH;
+
+       end += table->length;
+       while (p < end) {
+               h = (struct ivhd_header *)p;
+               switch (h->type) {
+               case ACPI_IVHD_TYPE:
+                       find_last_devid_from_ivhd(h);
+                       break;
+               default:
+                       break;
+               }
+               p += h->length;
+       }
+       WARN_ON(p != end);
+
+       return 0;
+}
+
+static u8 * __init alloc_command_buffer(struct amd_iommu *iommu)
+{
+       u8 *cmd_buf = (u8 *)__get_free_pages(GFP_KERNEL,
+                       get_order(CMD_BUFFER_SIZE));
+       u64 entry = 0;
+
+       if (cmd_buf == NULL)
+               return NULL;
+
+       iommu->cmd_buf_size = CMD_BUFFER_SIZE;
+
+       memset(cmd_buf, 0, CMD_BUFFER_SIZE);
+
+       entry = (u64)virt_to_phys(cmd_buf);
+       entry |= MMIO_CMD_SIZE_512;
+       memcpy_toio(iommu->mmio_base + MMIO_CMD_BUF_OFFSET,
+                       &entry, sizeof(entry));
+
+       iommu_feature_enable(iommu, CONTROL_CMDBUF_EN);
+
+       return cmd_buf;
+}
+
+static void __init free_command_buffer(struct amd_iommu *iommu)
+{
+       if (iommu->cmd_buf)
+               free_pages((unsigned long)iommu->cmd_buf,
+                               get_order(CMD_BUFFER_SIZE));
+}
+
+static void set_dev_entry_bit(u16 devid, u8 bit)
+{
+       int i = (bit >> 5) & 0x07;
+       int _bit = bit & 0x1f;
+
+       amd_iommu_dev_table[devid].data[i] |= (1 << _bit);
+}
+
+static void __init set_dev_entry_from_acpi(u16 devid, u32 flags, u32 ext_flags)
+{
+       if (flags & ACPI_DEVFLAG_INITPASS)
+               set_dev_entry_bit(devid, DEV_ENTRY_INIT_PASS);
+       if (flags & ACPI_DEVFLAG_EXTINT)
+               set_dev_entry_bit(devid, DEV_ENTRY_EINT_PASS);
+       if (flags & ACPI_DEVFLAG_NMI)
+               set_dev_entry_bit(devid, DEV_ENTRY_NMI_PASS);
+       if (flags & ACPI_DEVFLAG_SYSMGT1)
+               set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT1);
+       if (flags & ACPI_DEVFLAG_SYSMGT2)
+               set_dev_entry_bit(devid, DEV_ENTRY_SYSMGT2);
+       if (flags & ACPI_DEVFLAG_LINT0)
+               set_dev_entry_bit(devid, DEV_ENTRY_LINT0_PASS);
+       if (flags & ACPI_DEVFLAG_LINT1)
+               set_dev_entry_bit(devid, DEV_ENTRY_LINT1_PASS);
+}
+
+static void __init set_iommu_for_device(struct amd_iommu *iommu, u16 devid)
+{
+       amd_iommu_rlookup_table[devid] = iommu;
+}
+
+static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
+{
+       struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+
+       if (!(m->flags & IVMD_FLAG_EXCL_RANGE))
+               return;
+
+       if (iommu) {
+               set_dev_entry_bit(m->devid, DEV_ENTRY_EX);
+               iommu->exclusion_start = m->range_start;
+               iommu->exclusion_length = m->range_length;
+       }
+}
+
+static void __init init_iommu_from_pci(struct amd_iommu *iommu)
+{
+       int bus = PCI_BUS(iommu->devid);
+       int dev = PCI_SLOT(iommu->devid);
+       int fn  = PCI_FUNC(iommu->devid);
+       int cap_ptr = iommu->cap_ptr;
+       u32 range;
+
+       iommu->cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_CAP_HDR_OFFSET);
+
+       range = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET);
+       iommu->first_device = DEVID(MMIO_GET_BUS(range), MMIO_GET_FD(range));
+       iommu->last_device = DEVID(MMIO_GET_BUS(range), MMIO_GET_LD(range));
+}
+
+static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
+                                       struct ivhd_header *h)
+{
+       u8 *p = (u8 *)h;
+       u8 *end = p, flags = 0;
+       u16 dev_i, devid = 0, devid_start = 0, devid_to = 0;
+       u32 ext_flags = 0;
+       bool alias = 0;
+       struct ivhd_entry *e;
+
+       /*
+        * First set the recommended feature enable bits from ACPI
+        * into the IOMMU control registers
+        */
+       h->flags & IVHD_FLAG_HT_TUN_EN ?
+               iommu_feature_enable(iommu, CONTROL_HT_TUN_EN) :
+               iommu_feature_disable(iommu, CONTROL_HT_TUN_EN);
+
+       h->flags & IVHD_FLAG_PASSPW_EN ?
+               iommu_feature_enable(iommu, CONTROL_PASSPW_EN) :
+               iommu_feature_disable(iommu, CONTROL_PASSPW_EN);
+
+       h->flags & IVHD_FLAG_RESPASSPW_EN ?
+               iommu_feature_enable(iommu, CONTROL_RESPASSPW_EN) :
+               iommu_feature_disable(iommu, CONTROL_RESPASSPW_EN);
+
+       h->flags & IVHD_FLAG_ISOC_EN ?
+               iommu_feature_enable(iommu, CONTROL_ISOC_EN) :
+               iommu_feature_disable(iommu, CONTROL_ISOC_EN);
+
+       /*
+        * make IOMMU memory accesses cache coherent
+        */
+       iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
+
+       /*
+        * Done. Now parse the device entries
+        */
+       p += sizeof(struct ivhd_header);
+       end += h->length;
+
+       while (p < end) {
+               e = (struct ivhd_entry *)p;
+               switch (e->type) {
+               case IVHD_DEV_ALL:
+                       for (dev_i = iommu->first_device;
+                                       dev_i <= iommu->last_device; ++dev_i)
+                               set_dev_entry_from_acpi(dev_i, e->flags, 0);
+                       break;
+               case IVHD_DEV_SELECT:
+                       devid = e->devid;
+                       set_dev_entry_from_acpi(devid, e->flags, 0);
+                       break;
+               case IVHD_DEV_SELECT_RANGE_START:
+                       devid_start = e->devid;
+                       flags = e->flags;
+                       ext_flags = 0;
+                       alias = 0;
+                       break;
+               case IVHD_DEV_ALIAS:
+                       devid = e->devid;
+                       devid_to = e->ext >> 8;
+                       set_dev_entry_from_acpi(devid, e->flags, 0);
+                       amd_iommu_alias_table[devid] = devid_to;
+                       break;
+               case IVHD_DEV_ALIAS_RANGE:
+                       devid_start = e->devid;
+                       flags = e->flags;
+                       devid_to = e->ext >> 8;
+                       ext_flags = 0;
+                       alias = 1;
+                       break;
+               case IVHD_DEV_EXT_SELECT:
+                       devid = e->devid;
+                       set_dev_entry_from_acpi(devid, e->flags, e->ext);
+                       break;
+               case IVHD_DEV_EXT_SELECT_RANGE:
+                       devid_start = e->devid;
+                       flags = e->flags;
+                       ext_flags = e->ext;
+                       alias = 0;
+                       break;
+               case IVHD_DEV_RANGE_END:
+                       devid = e->devid;
+                       for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
+                               if (alias)
+                                       amd_iommu_alias_table[dev_i] = devid_to;
+                               set_dev_entry_from_acpi(
+                                               amd_iommu_alias_table[dev_i],
+                                               flags, ext_flags);
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               p += 0x04 << (e->type >> 6);
+       }
+}
+
+static int __init init_iommu_devices(struct amd_iommu *iommu)
+{
+       u16 i;
+
+       for (i = iommu->first_device; i <= iommu->last_device; ++i)
+               set_iommu_for_device(iommu, i);
+
+       return 0;
+}
+
+static void __init free_iommu_one(struct amd_iommu *iommu)
+{
+       free_command_buffer(iommu);
+       iommu_unmap_mmio_space(iommu);
+}
+
+static void __init free_iommu_all(void)
+{
+       struct amd_iommu *iommu, *next;
+
+       list_for_each_entry_safe(iommu, next, &amd_iommu_list, list) {
+               list_del(&iommu->list);
+               free_iommu_one(iommu);
+               kfree(iommu);
+       }
+}
+
+static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
+{
+       spin_lock_init(&iommu->lock);
+       list_add_tail(&iommu->list, &amd_iommu_list);
+
+       /*
+        * Copy data from ACPI table entry to the iommu struct
+        */
+       iommu->devid = h->devid;
+       iommu->cap_ptr = h->cap_ptr;
+       iommu->mmio_phys = h->mmio_phys;
+       iommu->mmio_base = iommu_map_mmio_space(h->mmio_phys);
+       if (!iommu->mmio_base)
+               return -ENOMEM;
+
+       iommu_set_device_table(iommu);
+       iommu->cmd_buf = alloc_command_buffer(iommu);
+       if (!iommu->cmd_buf)
+               return -ENOMEM;
+
+       init_iommu_from_pci(iommu);
+       init_iommu_from_acpi(iommu, h);
+       init_iommu_devices(iommu);
+
+       return 0;
+}
+
+static int __init init_iommu_all(struct acpi_table_header *table)
+{
+       u8 *p = (u8 *)table, *end = (u8 *)table;
+       struct ivhd_header *h;
+       struct amd_iommu *iommu;
+       int ret;
+
+       INIT_LIST_HEAD(&amd_iommu_list);
+
+       end += table->length;
+       p += IVRS_HEADER_LENGTH;
+
+       while (p < end) {
+               h = (struct ivhd_header *)p;
+               switch (*p) {
+               case ACPI_IVHD_TYPE:
+                       iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
+                       if (iommu == NULL)
+                               return -ENOMEM;
+                       ret = init_iommu_one(iommu, h);
+                       if (ret)
+                               return ret;
+                       break;
+               default:
+                       break;
+               }
+               p += h->length;
+
+       }
+       WARN_ON(p != end);
+
+       return 0;
+}
+
+static void __init free_unity_maps(void)
+{
+       struct unity_map_entry *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &amd_iommu_unity_map, list) {
+               list_del(&entry->list);
+               kfree(entry);
+       }
+}
+
+static int __init init_exclusion_range(struct ivmd_header *m)
+{
+       int i;
+
+       switch (m->type) {
+       case ACPI_IVMD_TYPE:
+               set_device_exclusion_range(m->devid, m);
+               break;
+       case ACPI_IVMD_TYPE_ALL:
+               for (i = 0; i < amd_iommu_last_bdf; ++i)
+                       set_device_exclusion_range(i, m);
+               break;
+       case ACPI_IVMD_TYPE_RANGE:
+               for (i = m->devid; i <= m->aux; ++i)
+                       set_device_exclusion_range(i, m);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int __init init_unity_map_range(struct ivmd_header *m)
+{
+       struct unity_map_entry *e = 0;
+
+       e = kzalloc(sizeof(*e), GFP_KERNEL);
+       if (e == NULL)
+               return -ENOMEM;
+
+       switch (m->type) {
+       default:
+       case ACPI_IVMD_TYPE:
+               e->devid_start = e->devid_end = m->devid;
+               break;
+       case ACPI_IVMD_TYPE_ALL:
+               e->devid_start = 0;
+               e->devid_end = amd_iommu_last_bdf;
+               break;
+       case ACPI_IVMD_TYPE_RANGE:
+               e->devid_start = m->devid;
+               e->devid_end = m->aux;
+               break;
+       }
+       e->address_start = PAGE_ALIGN(m->range_start);
+       e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
+       e->prot = m->flags >> 1;
+
+       list_add_tail(&e->list, &amd_iommu_unity_map);
+
+       return 0;
+}
+
+static int __init init_memory_definitions(struct acpi_table_header *table)
+{
+       u8 *p = (u8 *)table, *end = (u8 *)table;
+       struct ivmd_header *m;
+
+       INIT_LIST_HEAD(&amd_iommu_unity_map);
+
+       end += table->length;
+       p += IVRS_HEADER_LENGTH;
+
+       while (p < end) {
+               m = (struct ivmd_header *)p;
+               if (m->flags & IVMD_FLAG_EXCL_RANGE)
+                       init_exclusion_range(m);
+               else if (m->flags & IVMD_FLAG_UNITY_MAP)
+                       init_unity_map_range(m);
+
+               p += m->length;
+       }
+
+       return 0;
+}
+
+static void __init enable_iommus(void)
+{
+       struct amd_iommu *iommu;
+
+       list_for_each_entry(iommu, &amd_iommu_list, list) {
+               iommu_set_exclusion_range(iommu);
+               iommu_enable(iommu);
+       }
+}
+
+/*
+ * Suspend/Resume support
+ * disable suspend until real resume implemented
+ */
+
+static int amd_iommu_resume(struct sys_device *dev)
+{
+       return 0;
+}
+
+static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state)
+{
+       return -EINVAL;
+}
+
+static struct sysdev_class amd_iommu_sysdev_class = {
+       .name = "amd_iommu",
+       .suspend = amd_iommu_suspend,
+       .resume = amd_iommu_resume,
+};
+
+static struct sys_device device_amd_iommu = {
+       .id = 0,
+       .cls = &amd_iommu_sysdev_class,
+};
+
+int __init amd_iommu_init(void)
+{
+       int i, ret = 0;
+
+
+       if (no_iommu) {
+               printk(KERN_INFO "AMD IOMMU disabled by kernel command line\n");
+               return 0;
+       }
+
+       if (!amd_iommu_detected)
+               return -ENODEV;
+
+       /*
+        * First parse ACPI tables to find the largest Bus/Dev/Func
+        * we need to handle. Upon this information the shared data
+        * structures for the IOMMUs in the system will be allocated
+        */
+       if (acpi_table_parse("IVRS", find_last_devid_acpi) != 0)
+               return -ENODEV;
+
+       dev_table_size     = TBL_SIZE(DEV_TABLE_ENTRY_SIZE);
+       alias_table_size   = TBL_SIZE(ALIAS_TABLE_ENTRY_SIZE);
+       rlookup_table_size = TBL_SIZE(RLOOKUP_TABLE_ENTRY_SIZE);
+
+       ret = -ENOMEM;
+
+       /* Device table - directly used by all IOMMUs */
+       amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL,
+                                     get_order(dev_table_size));
+       if (amd_iommu_dev_table == NULL)
+               goto out;
+
+       /*
+        * Alias table - map PCI Bus/Dev/Func to Bus/Dev/Func the
+        * IOMMU see for that device
+        */
+       amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL,
+                       get_order(alias_table_size));
+       if (amd_iommu_alias_table == NULL)
+               goto free;
+
+       /* IOMMU rlookup table - find the IOMMU for a specific device */
+       amd_iommu_rlookup_table = (void *)__get_free_pages(GFP_KERNEL,
+                       get_order(rlookup_table_size));
+       if (amd_iommu_rlookup_table == NULL)
+               goto free;
+
+       /*
+        * Protection Domain table - maps devices to protection domains
+        * This table has the same size as the rlookup_table
+        */
+       amd_iommu_pd_table = (void *)__get_free_pages(GFP_KERNEL,
+                                    get_order(rlookup_table_size));
+       if (amd_iommu_pd_table == NULL)
+               goto free;
+
+       amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages(GFP_KERNEL,
+                                           get_order(MAX_DOMAIN_ID/8));
+       if (amd_iommu_pd_alloc_bitmap == NULL)
+               goto free;
+
+       /*
+        * memory is allocated now; initialize the device table with all zeroes
+        * and let all alias entries point to itself
+        */
+       memset(amd_iommu_dev_table, 0, dev_table_size);
+       for (i = 0; i < amd_iommu_last_bdf; ++i)
+               amd_iommu_alias_table[i] = i;
+
+       memset(amd_iommu_pd_table, 0, rlookup_table_size);
+       memset(amd_iommu_pd_alloc_bitmap, 0, MAX_DOMAIN_ID / 8);
+
+       /*
+        * never allocate domain 0 because its used as the non-allocated and
+        * error value placeholder
+        */
+       amd_iommu_pd_alloc_bitmap[0] = 1;
+
+       /*
+        * now the data structures are allocated and basically initialized
+        * start the real acpi table scan
+        */
+       ret = -ENODEV;
+       if (acpi_table_parse("IVRS", init_iommu_all) != 0)
+               goto free;
+
+       if (acpi_table_parse("IVRS", init_memory_definitions) != 0)
+               goto free;
+
+       ret = amd_iommu_init_dma_ops();
+       if (ret)
+               goto free;
+
+       ret = sysdev_class_register(&amd_iommu_sysdev_class);
+       if (ret)
+               goto free;
+
+       ret = sysdev_register(&device_amd_iommu);
+       if (ret)
+               goto free;
+
+       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");
+       else
+               printk("disabled\n");
+
+out:
+       return ret;
+
+free:
+       if (amd_iommu_pd_alloc_bitmap)
+               free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, 1);
+
+       if (amd_iommu_pd_table)
+               free_pages((unsigned long)amd_iommu_pd_table,
+                               get_order(rlookup_table_size));
+
+       if (amd_iommu_rlookup_table)
+               free_pages((unsigned long)amd_iommu_rlookup_table,
+                               get_order(rlookup_table_size));
+
+       if (amd_iommu_alias_table)
+               free_pages((unsigned long)amd_iommu_alias_table,
+                               get_order(alias_table_size));
+
+       if (amd_iommu_dev_table)
+               free_pages((unsigned long)amd_iommu_dev_table,
+                               get_order(dev_table_size));
+
+       free_iommu_all();
+
+       free_unity_maps();
+
+       goto out;
+}
+
+static int __init early_amd_iommu_detect(struct acpi_table_header *table)
+{
+       return 0;
+}
+
+void __init amd_iommu_detect(void)
+{
+       if (swiotlb || no_iommu || iommu_detected)
+               return;
+
+       if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) {
+               iommu_detected = 1;
+               amd_iommu_detected = 1;
+#ifdef CONFIG_GART_IOMMU
+               gart_iommu_aperture_disabled = 1;
+               gart_iommu_aperture = 0;
+#endif
+       }
+}
+
+static int __init parse_amd_iommu_options(char *str)
+{
+       for (; *str; ++str) {
+               if (strcmp(str, "isolate") == 0)
+                       amd_iommu_isolate = 1;
+       }
+
+       return 1;
+}
+
+static int __init parse_amd_iommu_size_options(char *str)
+{
+       for (; *str; ++str) {
+               if (strcmp(str, "32M") == 0)
+                       amd_iommu_aperture_order = 25;
+               if (strcmp(str, "64M") == 0)
+                       amd_iommu_aperture_order = 26;
+               if (strcmp(str, "128M") == 0)
+                       amd_iommu_aperture_order = 27;
+               if (strcmp(str, "256M") == 0)
+                       amd_iommu_aperture_order = 28;
+               if (strcmp(str, "512M") == 0)
+                       amd_iommu_aperture_order = 29;
+               if (strcmp(str, "1G") == 0)
+                       amd_iommu_aperture_order = 30;
+       }
+
+       return 1;
+}
+
+__setup("amd_iommu=", parse_amd_iommu_options);
+__setup("amd_iommu_size=", parse_amd_iommu_size_options);
index 479926d9e0048d242023def47b3f596550a13344..9f907806c1a53d58f9be603bb18bdcb60f14c6c2 100644 (file)
@@ -35,6 +35,18 @@ int fallback_aper_force __initdata;
 
 int fix_aperture __initdata = 1;
 
+struct bus_dev_range {
+       int bus;
+       int dev_base;
+       int dev_limit;
+};
+
+static struct bus_dev_range bus_dev_ranges[] __initdata = {
+       { 0x00, 0x18, 0x20},
+       { 0xff, 0x00, 0x20},
+       { 0xfe, 0x00, 0x20}
+};
+
 static struct resource gart_resource = {
        .name   = "GART",
        .flags  = IORESOURCE_MEM,
@@ -55,8 +67,9 @@ static u32 __init allocate_aperture(void)
        u32 aper_size;
        void *p;
 
-       if (fallback_aper_order > 7)
-               fallback_aper_order = 7;
+       /* aper_size should <= 1G */
+       if (fallback_aper_order > 5)
+               fallback_aper_order = 5;
        aper_size = (32 * 1024 * 1024) << fallback_aper_order;
 
        /*
@@ -65,7 +78,20 @@ static u32 __init allocate_aperture(void)
         * memory. Unfortunately we cannot move it up because that would
         * make the IOMMU useless.
         */
-       p = __alloc_bootmem_nopanic(aper_size, aper_size, 0);
+       /*
+        * using 512M as goal, in case kexec will load kernel_big
+        * that will do the on position decompress, and  could overlap with
+        * that positon with gart that is used.
+        * sequende:
+        * kernel_small
+        * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
+        * ==> kernel_small(gart area become e820_reserved)
+        * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
+        * ==> kerne_big (uncompressed size will be big than 64M or 128M)
+        * so don't use 512M below as gart iommu, leave the space for kernel
+        * code for safe
+        */
+       p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20);
        if (!p || __pa(p)+aper_size > 0xffffffff) {
                printk(KERN_ERR
                        "Cannot allocate aperture memory hole (%p,%uK)\n",
@@ -83,69 +109,53 @@ static u32 __init allocate_aperture(void)
        return (u32)__pa(p);
 }
 
-static int __init aperture_valid(u64 aper_base, u32 aper_size)
-{
-       if (!aper_base)
-               return 0;
-
-       if (aper_base + aper_size > 0x100000000UL) {
-               printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
-               return 0;
-       }
-       if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
-               printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n");
-               return 0;
-       }
-       if (aper_size < 64*1024*1024) {
-               printk(KERN_ERR "Aperture too small (%d MB)\n", aper_size>>20);
-               return 0;
-       }
-
-       return 1;
-}
 
 /* Find a PCI capability */
-static __u32 __init find_cap(int num, int slot, int func, int cap)
+static u32 __init find_cap(int bus, int slot, int func, int cap)
 {
        int bytes;
        u8 pos;
 
-       if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+       if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) &
                                                PCI_STATUS_CAP_LIST))
                return 0;
 
-       pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+       pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST);
        for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
                u8 id;
 
                pos &= ~3;
-               id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+               id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID);
                if (id == 0xff)
                        break;
                if (id == cap)
                        return pos;
-               pos = read_pci_config_byte(num, slot, func,
+               pos = read_pci_config_byte(bus, slot, func,
                                                pos+PCI_CAP_LIST_NEXT);
        }
        return 0;
 }
 
 /* Read a standard AGPv3 bridge header */
-static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
+static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order)
 {
        u32 apsize;
        u32 apsizereg;
        int nbits;
        u32 aper_low, aper_hi;
        u64 aper;
+       u32 old_order;
 
-       printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", num, slot, func);
-       apsizereg = read_pci_config_16(num, slot, func, cap + 0x14);
+       printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", bus, slot, func);
+       apsizereg = read_pci_config_16(bus, slot, func, cap + 0x14);
        if (apsizereg == 0xffffffff) {
                printk(KERN_ERR "APSIZE in AGP bridge unreadable\n");
                return 0;
        }
 
+       /* old_order could be the value from NB gart setting */
+       old_order = *order;
+
        apsize = apsizereg & 0xfff;
        /* Some BIOS use weird encodings not in the AGPv3 table. */
        if (apsize & 0xff)
@@ -155,14 +165,26 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
        if ((int)*order < 0) /* < 32MB */
                *order = 0;
 
-       aper_low = read_pci_config(num, slot, func, 0x10);
-       aper_hi = read_pci_config(num, slot, func, 0x14);
+       aper_low = read_pci_config(bus, slot, func, 0x10);
+       aper_hi = read_pci_config(bus, slot, func, 0x14);
        aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
 
+       /*
+        * On some sick chips, APSIZE is 0. It means it wants 4G
+        * so let double check that order, and lets trust AMD NB settings:
+        */
+       printk(KERN_INFO "Aperture from AGP @ %Lx old size %u MB\n",
+                       aper, 32 << old_order);
+       if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) {
+               printk(KERN_INFO "Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n",
+                               32 << *order, apsizereg);
+               *order = old_order;
+       }
+
        printk(KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
                        aper, 32 << *order, apsizereg);
 
-       if (!aperture_valid(aper, (32*1024*1024) << *order))
+       if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20))
                return 0;
        return (u32)aper;
 }
@@ -180,17 +202,17 @@ static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
  * the AGP bridges should be always an own bus on the HT hierarchy,
  * but do it here for future safety.
  */
-static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
+static u32 __init search_agp_bridge(u32 *order, int *valid_agp)
 {
-       int num, slot, func;
+       int bus, slot, func;
 
        /* Poor man's PCI discovery */
-       for (num = 0; num < 256; num++) {
+       for (bus = 0; bus < 256; bus++) {
                for (slot = 0; slot < 32; slot++) {
                        for (func = 0; func < 8; func++) {
                                u32 class, cap;
                                u8 type;
-                               class = read_pci_config(num, slot, func,
+                               class = read_pci_config(bus, slot, func,
                                                        PCI_CLASS_REVISION);
                                if (class == 0xffffffff)
                                        break;
@@ -199,17 +221,17 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
                                case PCI_CLASS_BRIDGE_HOST:
                                case PCI_CLASS_BRIDGE_OTHER: /* needed? */
                                        /* AGP bridge? */
-                                       cap = find_cap(num, slot, func,
+                                       cap = find_cap(bus, slot, func,
                                                        PCI_CAP_ID_AGP);
                                        if (!cap)
                                                break;
                                        *valid_agp = 1;
-                                       return read_agp(num, slot, func, cap,
+                                       return read_agp(bus, slot, func, cap,
                                                        order);
                                }
 
                                /* No multi-function device? */
-                               type = read_pci_config_byte(num, slot, func,
+                               type = read_pci_config_byte(bus, slot, func,
                                                               PCI_HEADER_TYPE);
                                if (!(type & 0x80))
                                        break;
@@ -249,36 +271,50 @@ void __init early_gart_iommu_check(void)
         * or BIOS forget to put that in reserved.
         * try to update e820 to make that region as reserved.
         */
-       int fix, num;
+       int i, fix, slot;
        u32 ctl;
        u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
        u64 aper_base = 0, last_aper_base = 0;
-       int aper_enabled = 0, last_aper_enabled = 0;
+       int aper_enabled = 0, last_aper_enabled = 0, last_valid = 0;
 
        if (!early_pci_allowed())
                return;
 
+       /* This is mostly duplicate of iommu_hole_init */
        fix = 0;
-       for (num = 24; num < 32; num++) {
-               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
-                       continue;
-
-               ctl = read_pci_config(0, num, 3, 0x90);
-               aper_enabled = ctl & 1;
-               aper_order = (ctl >> 1) & 7;
-               aper_size = (32 * 1024 * 1024) << aper_order;
-               aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
-               aper_base <<= 25;
-
-               if ((last_aper_order && aper_order != last_aper_order) ||
-                   (last_aper_base && aper_base != last_aper_base) ||
-                   (last_aper_enabled && aper_enabled != last_aper_enabled)) {
-                       fix = 1;
-                       break;
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
+                       aper_enabled = ctl & AMD64_GARTEN;
+                       aper_order = (ctl >> 1) & 7;
+                       aper_size = (32 * 1024 * 1024) << aper_order;
+                       aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
+                       aper_base <<= 25;
+
+                       if (last_valid) {
+                               if ((aper_order != last_aper_order) ||
+                                   (aper_base != last_aper_base) ||
+                                   (aper_enabled != last_aper_enabled)) {
+                                       fix = 1;
+                                       break;
+                               }
+                       }
+
+                       last_aper_order = aper_order;
+                       last_aper_base = aper_base;
+                       last_aper_enabled = aper_enabled;
+                       last_valid = 1;
                }
-               last_aper_order = aper_order;
-               last_aper_base = aper_base;
-               last_aper_enabled = aper_enabled;
        }
 
        if (!fix && !aper_enabled)
@@ -290,32 +326,46 @@ void __init early_gart_iommu_check(void)
        if (gart_fix_e820 && !fix && aper_enabled) {
                if (e820_any_mapped(aper_base, aper_base + aper_size,
                                    E820_RAM)) {
-                       /* reserved it, so we can resuse it in second kernel */
+                       /* reserve it, so we can reuse it in second kernel */
                        printk(KERN_INFO "update e820 for GART\n");
-                       add_memory_region(aper_base, aper_size, E820_RESERVED);
+                       e820_add_region(aper_base, aper_size, E820_RESERVED);
                        update_e820();
                }
-               return;
        }
 
+       if (!fix)
+               return;
+
        /* different nodes have different setting, disable them all at first*/
-       for (num = 24; num < 32; num++) {
-               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
-                       continue;
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
 
-               ctl = read_pci_config(0, num, 3, 0x90);
-               ctl &= ~1;
-               write_pci_config(0, num, 3, 0x90, ctl);
+                       ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
+                       ctl &= ~AMD64_GARTEN;
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
+               }
        }
 
 }
 
+static int __initdata printed_gart_size_msg;
+
 void __init gart_iommu_hole_init(void)
 {
+       u32 agp_aper_base = 0, agp_aper_order = 0;
        u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
        u64 aper_base, last_aper_base = 0;
-       int fix, num, valid_agp = 0;
-       int node;
+       int fix, slot, valid_agp = 0;
+       int i, node;
 
        if (gart_iommu_aperture_disabled || !fix_aperture ||
            !early_pci_allowed())
@@ -323,38 +373,65 @@ void __init gart_iommu_hole_init(void)
 
        printk(KERN_INFO  "Checking aperture...\n");
 
+       if (!fallback_aper_force)
+               agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp);
+
        fix = 0;
        node = 0;
-       for (num = 24; num < 32; num++) {
-               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
-                       continue;
-
-               iommu_detected = 1;
-               gart_iommu_aperture = 1;
-
-               aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7;
-               aper_size = (32 * 1024 * 1024) << aper_order;
-               aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
-               aper_base <<= 25;
-
-               printk(KERN_INFO "Node %d: aperture @ %Lx size %u MB\n",
-                               node, aper_base, aper_size >> 20);
-               node++;
-
-               if (!aperture_valid(aper_base, aper_size)) {
-                       fix = 1;
-                       break;
-               }
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       iommu_detected = 1;
+                       gart_iommu_aperture = 1;
+
+                       aper_order = (read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL) >> 1) & 7;
+                       aper_size = (32 * 1024 * 1024) << aper_order;
+                       aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
+                       aper_base <<= 25;
+
+                       printk(KERN_INFO "Node %d: aperture @ %Lx size %u MB\n",
+                                       node, aper_base, aper_size >> 20);
+                       node++;
+
+                       if (!aperture_valid(aper_base, aper_size, 64<<20)) {
+                               if (valid_agp && agp_aper_base &&
+                                   agp_aper_base == aper_base &&
+                                   agp_aper_order == aper_order) {
+                                       /* the same between two setting from NB and agp */
+                                       if (!no_iommu &&
+                                           max_pfn > MAX_DMA32_PFN &&
+                                           !printed_gart_size_msg) {
+                                               printk(KERN_ERR "you are using iommu with agp, but GART size is less than 64M\n");
+                                               printk(KERN_ERR "please increase GART size in your BIOS setup\n");
+                                               printk(KERN_ERR "if BIOS doesn't have that option, contact your HW vendor!\n");
+                                               printed_gart_size_msg = 1;
+                                       }
+                               } else {
+                                       fix = 1;
+                                       goto out;
+                               }
+                       }
 
-               if ((last_aper_order && aper_order != last_aper_order) ||
-                   (last_aper_base && aper_base != last_aper_base)) {
-                       fix = 1;
-                       break;
+                       if ((last_aper_order && aper_order != last_aper_order) ||
+                           (last_aper_base && aper_base != last_aper_base)) {
+                               fix = 1;
+                               goto out;
+                       }
+                       last_aper_order = aper_order;
+                       last_aper_base = aper_base;
                }
-               last_aper_order = aper_order;
-               last_aper_base = aper_base;
        }
 
+out:
        if (!fix && !fallback_aper_force) {
                if (last_aper_base) {
                        unsigned long n = (32 * 1024 * 1024) << last_aper_order;
@@ -364,14 +441,16 @@ void __init gart_iommu_hole_init(void)
                return;
        }
 
-       if (!fallback_aper_force)
-               aper_alloc = search_agp_bridge(&aper_order, &valid_agp);
+       if (!fallback_aper_force) {
+               aper_alloc = agp_aper_base;
+               aper_order = agp_aper_order;
+       }
 
        if (aper_alloc) {
                /* Got the aperture from the AGP bridge */
        } else if (swiotlb && !valid_agp) {
                /* Do nothing */
-       } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) ||
+       } else if ((!no_iommu && max_pfn > MAX_DMA32_PFN) ||
                   force_iommu ||
                   valid_agp ||
                   fallback_aper_force) {
@@ -401,16 +480,24 @@ void __init gart_iommu_hole_init(void)
        }
 
        /* Fix up the north bridges */
-       for (num = 24; num < 32; num++) {
-               if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
-                       continue;
-
-               /*
-                * Don't enable translation yet. That is done later.
-                * Assume this BIOS didn't initialise the GART so
-                * just overwrite all previous bits
-                */
-               write_pci_config(0, num, 3, 0x90, aper_order<<1);
-               write_pci_config(0, num, 3, 0x94, aper_alloc>>25);
+       for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
+               int bus;
+               int dev_base, dev_limit;
+
+               bus = bus_dev_ranges[i].bus;
+               dev_base = bus_dev_ranges[i].dev_base;
+               dev_limit = bus_dev_ranges[i].dev_limit;
+               for (slot = dev_base; slot < dev_limit; slot++) {
+                       if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
+                               continue;
+
+                       /* Don't enable translation yet. That is done later.
+                          Assume this BIOS didn't initialise the GART so
+                          just overwrite all previous bits */
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, aper_order << 1);
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25);
+               }
        }
+
+       set_up_gart_resume(aper_order, aper_alloc);
 }
index 4b99b1bdeb6cbb090e5868138922b259da7d98fe..3e58b676d23b8fd96a87823e30fcc4566d60aad6 100644 (file)
 
 unsigned long mp_lapic_addr;
 
-DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
-EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
-
 /*
  * Knob to control our willingness to enable the local APIC.
  *
- * -1=force-disable, +1=force-enable
+ * +1=force-enable
  */
-static int enable_local_apic __initdata;
+static int force_enable_local_apic;
+int disable_apic;
 
 /* Local APIC timer verification ok */
 static int local_apic_timer_verify_ok;
-/* Disable local APIC timer from the kernel commandline or via dmi quirk
-   or using CPU MSR check */
-int local_apic_timer_disabled;
+/* Disable local APIC timer from the kernel commandline or via dmi quirk */
+static int local_apic_timer_disabled;
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
 
+int first_system_vector = 0xfe;
+
+char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
+
 /*
  * Debug level, exported for io_apic.c
  */
 int apic_verbosity;
 
+int pic_mode;
+
+/* Have we found an MP table */
+int smp_found_config;
+
+static struct resource lapic_resource = {
+       .name = "Local APIC",
+       .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
+};
+
 static unsigned int calibration_result;
 
 static int lapic_next_event(unsigned long delta,
@@ -545,7 +556,7 @@ void __init setup_boot_APIC_clock(void)
                        lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
                else
                        printk(KERN_WARNING "APIC timer registered as dummy,"
-                              " due to nmi_watchdog=1!\n");
+                               " due to nmi_watchdog=%d!\n", nmi_watchdog);
        }
 
        /* Setup the lapic or request the broadcast */
@@ -963,7 +974,7 @@ void __cpuinit setup_local_APIC(void)
         * Double-check whether this APIC is really registered.
         */
        if (!apic_id_registered())
-               BUG();
+               WARN_ON_ONCE(1);
 
        /*
         * Intel recommends to set DFR, LDR and TPR before enabling
@@ -1094,7 +1105,7 @@ static int __init detect_init_APIC(void)
        u32 h, l, features;
 
        /* Disabled by kernel option? */
-       if (enable_local_apic < 0)
+       if (disable_apic)
                return -1;
 
        switch (boot_cpu_data.x86_vendor) {
@@ -1117,7 +1128,7 @@ static int __init detect_init_APIC(void)
                 * Over-ride BIOS and try to enable the local APIC only if
                 * "lapic" specified.
                 */
-               if (enable_local_apic <= 0) {
+               if (!force_enable_local_apic) {
                        printk(KERN_INFO "Local APIC disabled by BIOS -- "
                               "you can enable it with \"lapic\"\n");
                        return -1;
@@ -1154,9 +1165,6 @@ static int __init detect_init_APIC(void)
        if (l & MSR_IA32_APICBASE_ENABLE)
                mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
 
-       if (nmi_watchdog != NMI_NONE && nmi_watchdog != NMI_DISABLED)
-               nmi_watchdog = NMI_LOCAL_APIC;
-
        printk(KERN_INFO "Found and enabled local APIC!\n");
 
        apic_pm_activate();
@@ -1195,36 +1203,6 @@ void __init init_apic_mappings(void)
        if (boot_cpu_physical_apicid == -1U)
                boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
 
-#ifdef CONFIG_X86_IO_APIC
-       {
-               unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
-               int i;
-
-               for (i = 0; i < nr_ioapics; i++) {
-                       if (smp_found_config) {
-                               ioapic_phys = mp_ioapics[i].mpc_apicaddr;
-                               if (!ioapic_phys) {
-                                       printk(KERN_ERR
-                                              "WARNING: bogus zero IO-APIC "
-                                              "address found in MPTABLE, "
-                                              "disabling IO/APIC support!\n");
-                                       smp_found_config = 0;
-                                       skip_ioapic_setup = 1;
-                                       goto fake_ioapic_page;
-                               }
-                       } else {
-fake_ioapic_page:
-                               ioapic_phys = (unsigned long)
-                                             alloc_bootmem_pages(PAGE_SIZE);
-                               ioapic_phys = __pa(ioapic_phys);
-                       }
-                       set_fixmap_nocache(idx, ioapic_phys);
-                       printk(KERN_DEBUG "mapped IOAPIC to %08lx (%08lx)\n",
-                              __fix_to_virt(idx), ioapic_phys);
-                       idx++;
-               }
-       }
-#endif
 }
 
 /*
@@ -1236,7 +1214,7 @@ int apic_version[MAX_APICS];
 
 int __init APIC_init_uniprocessor(void)
 {
-       if (enable_local_apic < 0)
+       if (disable_apic)
                clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
 
        if (!smp_found_config && !cpu_has_apic)
@@ -1265,10 +1243,14 @@ int __init APIC_init_uniprocessor(void)
 #ifdef CONFIG_CRASH_DUMP
        boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
 #endif
-       phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
+       physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
 
        setup_local_APIC();
 
+#ifdef CONFIG_X86_IO_APIC
+       if (!smp_found_config || skip_ioapic_setup || !nr_ioapics)
+#endif
+               localise_nmi_watchdog();
        end_local_APIC_setup();
 #ifdef CONFIG_X86_IO_APIC
        if (smp_found_config)
@@ -1351,13 +1333,13 @@ void __init smp_intr_init(void)
         * The reschedule interrupt is a CPU-to-CPU reschedule-helper
         * IPI, driven by wakeup.
         */
-       set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+       alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
 
        /* IPI for invalidation */
-       set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+       alloc_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
 
        /* IPI for generic function call */
-       set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+       alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 }
 #endif
 
@@ -1370,15 +1352,15 @@ void __init apic_intr_init(void)
        smp_intr_init();
 #endif
        /* self generated IPI for local APIC timer */
-       set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
+       alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
        /* IPI vectors for APIC spurious and error interrupts */
-       set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-       set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+       alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+       alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
        /* thermal monitor LVT interrupt */
 #ifdef CONFIG_X86_MCE_P4THERMAL
-       set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+       alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
 #endif
 }
 
@@ -1513,6 +1495,9 @@ void __cpuinit generic_processor_info(int apicid, int version)
                 */
                cpu = 0;
 
+       if (apicid > max_physical_apicid)
+               max_physical_apicid = apicid;
+
        /*
         * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y
         * but we need to work other dependencies like SMP_SUSPEND etc
@@ -1520,7 +1505,7 @@ void __cpuinit generic_processor_info(int apicid, int version)
         * if (CPU_HOTPLUG_ENABLED || num_processors > 8)
         *       - Ashok Raj <ashok.raj@intel.com>
         */
-       if (num_processors > 8) {
+       if (max_physical_apicid >= 8) {
                switch (boot_cpu_data.x86_vendor) {
                case X86_VENDOR_INTEL:
                        if (!APIC_XAPIC(version)) {
@@ -1534,9 +1519,9 @@ void __cpuinit generic_processor_info(int apicid, int version)
        }
 #ifdef CONFIG_SMP
        /* are we being called early in kernel startup? */
-       if (x86_cpu_to_apicid_early_ptr) {
-               u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr;
-               u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr;
+       if (early_per_cpu_ptr(x86_cpu_to_apicid)) {
+               u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
+               u16 *bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid);
 
                cpu_to_apicid[cpu] = apicid;
                bios_cpu_apicid[cpu] = apicid;
@@ -1703,14 +1688,14 @@ static void apic_pm_activate(void) { }
  */
 static int __init parse_lapic(char *arg)
 {
-       enable_local_apic = 1;
+       force_enable_local_apic = 1;
        return 0;
 }
 early_param("lapic", parse_lapic);
 
 static int __init parse_nolapic(char *arg)
 {
-       enable_local_apic = -1;
+       disable_apic = 1;
        clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
        return 0;
 }
@@ -1740,3 +1725,21 @@ static int __init apic_set_verbosity(char *str)
 }
 __setup("apic=", apic_set_verbosity);
 
+static int __init lapic_insert_resource(void)
+{
+       if (!apic_phys)
+               return -1;
+
+       /* Put local APIC into the resource map. */
+       lapic_resource.start = apic_phys;
+       lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1;
+       insert_resource(&iomem_resource, &lapic_resource);
+
+       return 0;
+}
+
+/*
+ * need call insert after e820_reserve_resources()
+ * that is using request_resource
+ */
+late_initcall(lapic_insert_resource);
index 0633cfd0dc291a1310f0632e1012cf663b5e89a9..1e3d32e27c14c23a8d48d1dc6bcf8b30faeefae7 100644 (file)
@@ -43,7 +43,7 @@
 #include <mach_ipi.h>
 #include <mach_apic.h>
 
-int disable_apic_timer __cpuinitdata;
+static int disable_apic_timer __cpuinitdata;
 static int apic_calibrate_pmtmr __initdata;
 int disable_apic;
 
@@ -56,6 +56,9 @@ EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
  */
 int apic_verbosity;
 
+/* Have we found an MP table */
+int smp_found_config;
+
 static struct resource lapic_resource = {
        .name = "Local APIC",
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
@@ -87,9 +90,6 @@ static unsigned long apic_phys;
 
 unsigned long mp_lapic_addr;
 
-DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID;
-EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
-
 unsigned int __cpuinitdata maxcpus = NR_CPUS;
 /*
  * Get the LAPIC version
@@ -417,37 +417,13 @@ void __init setup_boot_APIC_clock(void)
                lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
        else
                printk(KERN_WARNING "APIC timer registered as dummy,"
-                      " due to nmi_watchdog=1!\n");
+                       " due to nmi_watchdog=%d!\n", nmi_watchdog);
 
        setup_APIC_timer();
 }
 
-/*
- * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the
- * C1E flag only in the secondary CPU, so when we detect the wreckage
- * we already have enabled the boot CPU local apic timer. Check, if
- * disable_apic_timer is set and the DUMMY flag is cleared. If yes,
- * set the DUMMY flag again and force the broadcast mode in the
- * clockevents layer.
- */
-static void __cpuinit check_boot_apic_timer_broadcast(void)
-{
-       if (!disable_apic_timer ||
-           (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
-               return;
-
-       printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
-       lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
-
-       local_irq_enable();
-       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
-                          &boot_cpu_physical_apicid);
-       local_irq_disable();
-}
-
 void __cpuinit setup_secondary_APIC_clock(void)
 {
-       check_boot_apic_timer_broadcast();
        setup_APIC_timer();
 }
 
@@ -850,7 +826,6 @@ static void __cpuinit lapic_setup_esr(void)
 void __cpuinit end_local_APIC_setup(void)
 {
        lapic_setup_esr();
-       nmi_watchdog_default();
        setup_apic_nmi_watchdog(NULL);
        apic_pm_activate();
 }
@@ -875,7 +850,7 @@ static int __init detect_init_APIC(void)
 
 void __init early_init_lapic_mapping(void)
 {
-       unsigned long apic_phys;
+       unsigned long phys_addr;
 
        /*
         * If no local APIC can be found then go out
@@ -884,11 +859,11 @@ void __init early_init_lapic_mapping(void)
        if (!smp_found_config)
                return;
 
-       apic_phys = mp_lapic_addr;
+       phys_addr = mp_lapic_addr;
 
-       set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
+       set_fixmap_nocache(FIX_APIC_BASE, phys_addr);
        apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
-                                APIC_BASE, apic_phys);
+                   APIC_BASE, phys_addr);
 
        /*
         * Fetch the APIC ID of the BSP in case we have a
@@ -942,7 +917,9 @@ int __init APIC_init_uniprocessor(void)
 
        verify_local_APIC();
 
-       phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
+       connect_bsp_APIC();
+
+       physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
        apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid));
 
        setup_local_APIC();
@@ -954,6 +931,8 @@ int __init APIC_init_uniprocessor(void)
        if (!skip_ioapic_setup && nr_ioapics)
                enable_IO_APIC();
 
+       if (!smp_found_config || skip_ioapic_setup || !nr_ioapics)
+               localise_nmi_watchdog();
        end_local_APIC_setup();
 
        if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
@@ -1021,6 +1000,14 @@ asmlinkage void smp_error_interrupt(void)
        irq_exit();
 }
 
+/**
+ *  * connect_bsp_APIC - attach the APIC to the interrupt system
+ *   */
+void __init connect_bsp_APIC(void)
+{
+       enable_apic_mode();
+}
+
 void disconnect_bsp_APIC(int virt_wire_setup)
 {
        /* Go back to Virtual Wire compatibility mode */
@@ -1090,10 +1077,13 @@ void __cpuinit generic_processor_info(int apicid, int version)
                 */
                cpu = 0;
        }
+       if (apicid > max_physical_apicid)
+               max_physical_apicid = apicid;
+
        /* are we being called early in kernel startup? */
-       if (x86_cpu_to_apicid_early_ptr) {
-               u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr;
-               u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr;
+       if (early_per_cpu_ptr(x86_cpu_to_apicid)) {
+               u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
+               u16 *bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid);
 
                cpu_to_apicid[cpu] = apicid;
                bios_cpu_apicid[cpu] = apicid;
@@ -1269,7 +1259,7 @@ __cpuinit int apic_is_clustered_box(void)
        if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && !is_vsmp_box())
                return 0;
 
-       bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr;
+       bios_cpu_apicid = early_per_cpu_ptr(x86_bios_cpu_apicid);
        bitmap_zero(clustermap, NUM_APIC_CLUSTERS);
 
        for (i = 0; i < NR_CPUS; i++) {
index bf9290e290136a36d6006d032c1ca4fe392f84bd..00e6d1370954cea194647e68312b1c80ddb66932 100644 (file)
 #include <linux/suspend.h>
 #include <linux/kthread.h>
 #include <linux/jiffies.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -1149,7 +1150,7 @@ static void queue_event(apm_event_t event, struct apm_user *sender)
                                as->event_tail = 0;
                }
                as->events[as->event_head] = event;
-               if ((!as->suser) || (!as->writer))
+               if (!as->suser || !as->writer)
                        continue;
                switch (event) {
                case APM_SYS_SUSPEND:
@@ -1396,7 +1397,7 @@ static void apm_mainloop(void)
 
 static int check_apm_user(struct apm_user *as, const char *func)
 {
-       if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
+       if (as == NULL || as->magic != APM_BIOS_MAGIC) {
                printk(KERN_ERR "apm: %s passed bad filp\n", func);
                return 1;
        }
@@ -1459,18 +1460,19 @@ static unsigned int do_poll(struct file *fp, poll_table *wait)
        return 0;
 }
 
-static int do_ioctl(struct inode *inode, struct file *filp,
-                   u_int cmd, u_long arg)
+static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
 {
        struct apm_user *as;
+       int ret;
 
        as = filp->private_data;
        if (check_apm_user(as, "ioctl"))
                return -EIO;
-       if ((!as->suser) || (!as->writer))
+       if (!as->suser || !as->writer)
                return -EPERM;
        switch (cmd) {
        case APM_IOC_STANDBY:
+               lock_kernel();
                if (as->standbys_read > 0) {
                        as->standbys_read--;
                        as->standbys_pending--;
@@ -1479,8 +1481,10 @@ static int do_ioctl(struct inode *inode, struct file *filp,
                        queue_event(APM_USER_STANDBY, as);
                if (standbys_pending <= 0)
                        standby();
+               unlock_kernel();
                break;
        case APM_IOC_SUSPEND:
+               lock_kernel();
                if (as->suspends_read > 0) {
                        as->suspends_read--;
                        as->suspends_pending--;
@@ -1488,16 +1492,17 @@ static int do_ioctl(struct inode *inode, struct file *filp,
                } else
                        queue_event(APM_USER_SUSPEND, as);
                if (suspends_pending <= 0) {
-                       return suspend(1);
+                       ret = suspend(1);
                } else {
                        as->suspend_wait = 1;
                        wait_event_interruptible(apm_suspend_waitqueue,
                                        as->suspend_wait == 0);
-                       return as->suspend_result;
+                       ret = as->suspend_result;
                }
-               break;
+               unlock_kernel();
+               return ret;
        default:
-               return -EINVAL;
+               return -ENOTTY;
        }
        return 0;
 }
@@ -1860,7 +1865,7 @@ static const struct file_operations apm_bios_fops = {
        .owner          = THIS_MODULE,
        .read           = do_read,
        .poll           = do_poll,
-       .ioctl          = do_ioctl,
+       .unlocked_ioctl = do_ioctl,
        .open           = do_open,
        .release        = do_release,
 };
index 92588083950f8106bd08aafb081ebe46ce3023fd..6649d09ad88f8830df49427c7d8763196eb0a0f6 100644 (file)
@@ -111,7 +111,7 @@ void foo(void)
        OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
        OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
        OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
-       OFFSET(PV_CPU_irq_enable_syscall_ret, pv_cpu_ops, irq_enable_syscall_ret);
+       OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
        OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
 #endif
 
index f126c05d6170a17e8fdd880b5973324eb8ebb7d0..bacf5deeec2d13a16a675e2b6bc44e8f53ed232c 100644 (file)
@@ -34,7 +34,7 @@ int main(void)
        ENTRY(pid);
        BLANK();
 #undef ENTRY
-#define ENTRY(entry) DEFINE(threadinfo_ ## entry, offsetof(struct thread_info, entry))
+#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
        ENTRY(flags);
        ENTRY(addr_limit);
        ENTRY(preempt_count);
@@ -61,8 +61,11 @@ int main(void)
        OFFSET(PARAVIRT_PATCH_pv_irq_ops, paravirt_patch_template, pv_irq_ops);
        OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
        OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
+       OFFSET(PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame);
        OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
-       OFFSET(PV_CPU_irq_enable_syscall_ret, pv_cpu_ops, irq_enable_syscall_ret);
+       OFFSET(PV_CPU_usergs_sysret32, pv_cpu_ops, usergs_sysret32);
+       OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);
+       OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
        OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs);
        OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
 #endif
index a0c6f8190887f4220b4b76e531e57ad471fc1acb..ee76eaad300135f92c87973e80f2365a821efe27 100644 (file)
@@ -6,11 +6,15 @@ obj-y                 := intel_cacheinfo.o addon_cpuid_features.o
 obj-y                  += proc.o feature_names.o
 
 obj-$(CONFIG_X86_32)   += common.o bugs.o
+obj-$(CONFIG_X86_64)   += common_64.o bugs_64.o
 obj-$(CONFIG_X86_32)   += amd.o
+obj-$(CONFIG_X86_64)   += amd_64.o
 obj-$(CONFIG_X86_32)   += cyrix.o
 obj-$(CONFIG_X86_32)   += centaur.o
+obj-$(CONFIG_X86_64)   += centaur_64.o
 obj-$(CONFIG_X86_32)   += transmeta.o
 obj-$(CONFIG_X86_32)   += intel.o
+obj-$(CONFIG_X86_64)   += intel_64.o
 obj-$(CONFIG_X86_32)   += umc.o
 
 obj-$(CONFIG_X86_MCE)  += mcheck/
index c2e1ce33c7cb0e9a9bdab5d16c204c9a83447f7a..84a8220a6072c0425b9da95fbb28b5a309cbfda1 100644 (file)
@@ -1,9 +1,7 @@
-
 /*
  *     Routines to indentify additional cpu features that are scattered in
  *     cpuid space.
  */
-
 #include <linux/cpu.h>
 
 #include <asm/pat.h>
@@ -53,19 +51,20 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_PAT
 void __cpuinit validate_pat_support(struct cpuinfo_x86 *c)
 {
+       if (!cpu_has_pat)
+               pat_disable("PAT not supported by CPU.");
+
        switch (c->x86_vendor) {
-       case X86_VENDOR_AMD:
-               if (c->x86 >= 0xf && c->x86 <= 0x11)
-                       return;
-               break;
        case X86_VENDOR_INTEL:
                if (c->x86 == 0xF || (c->x86 == 6 && c->x86_model >= 15))
                        return;
                break;
+       case X86_VENDOR_AMD:
+       case X86_VENDOR_CENTAUR:
+       case X86_VENDOR_TRANSMETA:
+               return;
        }
 
-       pat_disable(cpu_has_pat ?
-                   "PAT disabled. Not yet verified on this CPU type." :
-                   "PAT not supported by CPU.");
+       pat_disable("PAT disabled. Not yet verified on this CPU type.");
 }
 #endif
index 245866828294c6be3fcf369d0ea76a0a3eed59cb..81a07ca65d4487d7f3133619210d287238ac411c 100644 (file)
 extern void vide(void);
 __asm__(".align 4\nvide: ret");
 
-#ifdef CONFIG_X86_LOCAL_APIC
-#define ENABLE_C1E_MASK         0x18000000
-#define CPUID_PROCESSOR_SIGNATURE       1
-#define CPUID_XFAM              0x0ff00000
-#define CPUID_XFAM_K8           0x00000000
-#define CPUID_XFAM_10H          0x00100000
-#define CPUID_XFAM_11H          0x00200000
-#define CPUID_XMOD              0x000f0000
-#define CPUID_XMOD_REV_F        0x00040000
-
-/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
-static __cpuinit int amd_apic_timer_broken(void)
-{
-       u32 lo, hi;
-       u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
-       switch (eax & CPUID_XFAM) {
-       case CPUID_XFAM_K8:
-               if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
-                       break;
-       case CPUID_XFAM_10H:
-       case CPUID_XFAM_11H:
-               rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
-               if (lo & ENABLE_C1E_MASK) {
-                       if (smp_processor_id() != boot_cpu_physical_apicid)
-                               printk(KERN_INFO "AMD C1E detected late. "
-                                      "        Force timer broadcast.\n");
-                       return 1;
-               }
-               break;
-       default:
-               /* err on the side of caution */
-               return 1;
-       }
-       return 0;
-}
-#endif
-
 int force_mwait __cpuinitdata;
 
 static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
@@ -297,11 +260,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
                        num_cache_leaves = 3;
        }
 
-#ifdef CONFIG_X86_LOCAL_APIC
-       if (amd_apic_timer_broken())
-               local_apic_timer_disabled = 1;
-#endif
-
        /* K6s reports MCEs but don't actually have all the MSRs */
        if (c->x86 < 6)
                clear_cpu_cap(c, X86_FEATURE_MCE);
diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c
new file mode 100644 (file)
index 0000000..7c36fb8
--- /dev/null
@@ -0,0 +1,222 @@
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/numa_64.h>
+#include <asm/mmconfig.h>
+#include <asm/cacheflush.h>
+
+#include <mach_apic.h>
+
+#include "cpu.h"
+
+int force_mwait __cpuinitdata;
+
+#ifdef CONFIG_NUMA
+static int __cpuinit nearby_node(int apicid)
+{
+       int i, node;
+
+       for (i = apicid - 1; i >= 0; i--) {
+               node = apicid_to_node[i];
+               if (node != NUMA_NO_NODE && node_online(node))
+                       return node;
+       }
+       for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
+               node = apicid_to_node[i];
+               if (node != NUMA_NO_NODE && node_online(node))
+                       return node;
+       }
+       return first_node(node_online_map); /* Shouldn't happen */
+}
+#endif
+
+/*
+ * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
+ * Assumes number of cores is a power of two.
+ */
+static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       unsigned bits;
+#ifdef CONFIG_NUMA
+       int cpu = smp_processor_id();
+       int node = 0;
+       unsigned apicid = hard_smp_processor_id();
+#endif
+       bits = c->x86_coreid_bits;
+
+       /* Low order bits define the core id (index of core in socket) */
+       c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
+       /* Convert the initial APIC ID into the socket ID */
+       c->phys_proc_id = c->initial_apicid >> bits;
+
+#ifdef CONFIG_NUMA
+       node = c->phys_proc_id;
+       if (apicid_to_node[apicid] != NUMA_NO_NODE)
+               node = apicid_to_node[apicid];
+       if (!node_online(node)) {
+               /* Two possibilities here:
+                  - The CPU is missing memory and no node was created.
+                  In that case try picking one from a nearby CPU
+                  - The APIC IDs differ from the HyperTransport node IDs
+                  which the K8 northbridge parsing fills in.
+                  Assume they are all increased by a constant offset,
+                  but in the same order as the HT nodeids.
+                  If that doesn't result in a usable node fall back to the
+                  path for the previous case.  */
+
+               int ht_nodeid = c->initial_apicid;
+
+               if (ht_nodeid >= 0 &&
+                   apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
+                       node = apicid_to_node[ht_nodeid];
+               /* Pick a nearby node */
+               if (!node_online(node))
+                       node = nearby_node(apicid);
+       }
+       numa_set_node(cpu, node);
+
+       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+#endif
+#endif
+}
+
+static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       unsigned bits, ecx;
+
+       /* Multi core CPU? */
+       if (c->extended_cpuid_level < 0x80000008)
+               return;
+
+       ecx = cpuid_ecx(0x80000008);
+
+       c->x86_max_cores = (ecx & 0xff) + 1;
+
+       /* CPU telling us the core id bits shift? */
+       bits = (ecx >> 12) & 0xF;
+
+       /* Otherwise recompute */
+       if (bits == 0) {
+               while ((1 << bits) < c->x86_max_cores)
+                       bits++;
+       }
+
+       c->x86_coreid_bits = bits;
+
+#endif
+}
+
+static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
+{
+       early_init_amd_mc(c);
+
+       /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
+       if (c->x86_power & (1<<8))
+               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+}
+
+static void __cpuinit init_amd(struct cpuinfo_x86 *c)
+{
+       unsigned level;
+
+#ifdef CONFIG_SMP
+       unsigned long value;
+
+       /*
+        * Disable TLB flush filter by setting HWCR.FFDIS on K8
+        * bit 6 of msr C001_0015
+        *
+        * Errata 63 for SH-B3 steppings
+        * Errata 122 for all steppings (F+ have it disabled by default)
+        */
+       if (c->x86 == 0xf) {
+               rdmsrl(MSR_K8_HWCR, value);
+               value |= 1 << 6;
+               wrmsrl(MSR_K8_HWCR, value);
+       }
+#endif
+
+       /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+          3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+       clear_cpu_cap(c, 0*32+31);
+
+       /* On C+ stepping K8 rep microcode works well for copy/memset */
+       if (c->x86 == 0xf) {
+               level = cpuid_eax(1);
+               if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)
+                       set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+       }
+       if (c->x86 == 0x10 || c->x86 == 0x11)
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+
+       /* Enable workaround for FXSAVE leak */
+       if (c->x86 >= 6)
+               set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
+
+       level = get_model_name(c);
+       if (!level) {
+               switch (c->x86) {
+               case 0xf:
+                       /* Should distinguish Models here, but this is only
+                          a fallback anyways. */
+                       strcpy(c->x86_model_id, "Hammer");
+                       break;
+               }
+       }
+       display_cacheinfo(c);
+
+       /* Multi core CPU? */
+       if (c->extended_cpuid_level >= 0x80000008)
+               amd_detect_cmp(c);
+
+       if (c->extended_cpuid_level >= 0x80000006 &&
+               (cpuid_edx(0x80000006) & 0xf000))
+               num_cache_leaves = 4;
+       else
+               num_cache_leaves = 3;
+
+       if (c->x86 >= 0xf && c->x86 <= 0x11)
+               set_cpu_cap(c, X86_FEATURE_K8);
+
+       /* MFENCE stops RDTSC speculation */
+       set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+
+       if (c->x86 == 0x10) {
+               /* do this for boot cpu */
+               if (c == &boot_cpu_data)
+                       check_enable_amd_mmconf_dmi();
+
+               fam10h_check_enable_mmcfg();
+       }
+
+       if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
+               unsigned long long tseg;
+
+               /*
+                * Split up direct mapping around the TSEG SMM area.
+                * Don't do it for gbpages because there seems very little
+                * benefit in doing so.
+                */
+               if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) {
+                   printk(KERN_DEBUG "tseg: %010llx\n", tseg);
+                   if ((tseg>>PMD_SHIFT) <
+                               (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) ||
+                       ((tseg>>PMD_SHIFT) <
+                               (max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) &&
+                        (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT))))
+                       set_memory_4k((unsigned long)__va(tseg), 1);
+               }
+       }
+}
+
+static struct cpu_dev amd_cpu_dev __cpuinitdata = {
+       .c_vendor       = "AMD",
+       .c_ident        = { "AuthenticAMD" },
+       .c_early_init   = early_init_amd,
+       .c_init         = init_amd,
+};
+
+cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
+
index 170d2f5523b2c6e04f4c28aa423077388bb3abce..1b1c56bb338f7de23f8ee65f4e53f155c0cc294c 100644 (file)
@@ -59,8 +59,12 @@ static void __init check_fpu(void)
                return;
        }
 
-/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */
-       /* Test for the divl bug.. */
+       /*
+        * trap_init() enabled FXSR and company _before_ testing for FP
+        * problems here.
+        *
+        * Test for the divl bug..
+        */
        __asm__("fninit\n\t"
                "fldl %1\n\t"
                "fdivl %2\n\t"
@@ -108,10 +112,15 @@ static void __init check_popad(void)
          "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
          : "=&a" (res)
          : "d" (inp)
-         : "ecx", "edi" );
-       /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
-       if (res != 12345678) printk( "Buggy.\n" );
-                       else printk( "OK.\n" );
+         : "ecx", "edi");
+       /*
+        * If this fails, it means that any user program may lock the
+        * CPU hard. Too bad.
+        */
+       if (res != 12345678)
+               printk("Buggy.\n");
+       else
+               printk("OK.\n");
 #endif
 }
 
@@ -137,7 +146,8 @@ static void __init check_config(void)
  * i486+ only features! (WP works in supervisor mode and the
  * new "invlpg" and "bswap" instructions)
  */
-#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP)
+#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || \
+       defined(CONFIG_X86_BSWAP)
        if (boot_cpu_data.x86 == 3)
                panic("Kernel requires i486+ for 'invlpg' and other features");
 #endif
@@ -170,6 +180,7 @@ void __init check_bugs(void)
        check_fpu();
        check_hlt();
        check_popad();
-       init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+       init_utsname()->machine[1] =
+               '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
        alternative_instructions();
 }
diff --git a/arch/x86/kernel/cpu/centaur_64.c b/arch/x86/kernel/cpu/centaur_64.c
new file mode 100644 (file)
index 0000000..1d181c4
--- /dev/null
@@ -0,0 +1,35 @@
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
+{
+       if (c->x86 == 0x6 && c->x86_model >= 0xf)
+               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
+       set_cpu_cap(c, X86_FEATURE_SYSENTER32);
+}
+
+static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
+{
+       if (c->x86 == 0x6 && c->x86_model >= 0xf) {
+               c->x86_cache_alignment = c->x86_clflush_size * 2;
+               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+       }
+       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+}
+
+static struct cpu_dev centaur_cpu_dev __cpuinitdata = {
+       .c_vendor       = "Centaur",
+       .c_ident        = { "CentaurHauls" },
+       .c_early_init   = early_init_centaur,
+       .c_init         = init_centaur,
+};
+
+cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev);
+
index d0463a9462477716bd065b5c822cd34e96812282..80ab20d4fa39913ce2a7b4ea5676883bb6f9d96f 100644 (file)
@@ -427,7 +427,7 @@ __setup("serialnumber", x86_serial_nr_setup);
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
-void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 {
        int i;
 
diff --git a/arch/x86/kernel/cpu/common_64.c b/arch/x86/kernel/cpu/common_64.c
new file mode 100644 (file)
index 0000000..7b8cc72
--- /dev/null
@@ -0,0 +1,681 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/kgdb.h>
+#include <linux/topology.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/msr.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/mtrr.h>
+#include <asm/mce.h>
+#include <asm/pat.h>
+#include <asm/numa.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/mpspec.h>
+#include <asm/apic.h>
+#include <mach_apic.h>
+#endif
+#include <asm/pda.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/atomic.h>
+#include <asm/proto.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/genapic.h>
+
+#include "cpu.h"
+
+/* We need valid kernel segments for data and code in long mode too
+ * IRET will check the segment types  kkeil 2000/10/28
+ * Also sysret mandates a special GDT layout
+ */
+/* The TLS descriptors are currently at a different place compared to i386.
+   Hopefully nobody expects them at a fixed place (Wine?) */
+DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
+       [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } },
+       [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } },
+       [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } },
+       [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } },
+       [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } },
+       [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } },
+} };
+EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
+
+__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
+
+/* Current gdt points %fs at the "master" per-cpu area: after this,
+ * it's on the real one. */
+void switch_to_new_gdt(void)
+{
+       struct desc_ptr gdt_descr;
+
+       gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
+       gdt_descr.size = GDT_SIZE - 1;
+       load_gdt(&gdt_descr);
+}
+
+struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = {};
+
+static void __cpuinit default_init(struct cpuinfo_x86 *c)
+{
+       display_cacheinfo(c);
+}
+
+static struct cpu_dev __cpuinitdata default_cpu = {
+       .c_init = default_init,
+       .c_vendor = "Unknown",
+};
+static struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
+
+int __cpuinit get_model_name(struct cpuinfo_x86 *c)
+{
+       unsigned int *v;
+
+       if (c->extended_cpuid_level < 0x80000004)
+               return 0;
+
+       v = (unsigned int *) c->x86_model_id;
+       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+       c->x86_model_id[48] = 0;
+       return 1;
+}
+
+
+void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
+{
+       unsigned int n, dummy, ebx, ecx, edx;
+
+       n = c->extended_cpuid_level;
+
+       if (n >= 0x80000005) {
+               cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
+               printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), "
+                      "D cache %dK (%d bytes/line)\n",
+                      edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
+               c->x86_cache_size = (ecx>>24) + (edx>>24);
+               /* On K8 L1 TLB is inclusive, so don't count it */
+               c->x86_tlbsize = 0;
+       }
+
+       if (n >= 0x80000006) {
+               cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
+               ecx = cpuid_ecx(0x80000006);
+               c->x86_cache_size = ecx >> 16;
+               c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
+
+               printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
+               c->x86_cache_size, ecx & 0xFF);
+       }
+}
+
+void __cpuinit detect_ht(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_SMP
+       u32 eax, ebx, ecx, edx;
+       int index_msb, core_bits;
+
+       cpuid(1, &eax, &ebx, &ecx, &edx);
+
+
+       if (!cpu_has(c, X86_FEATURE_HT))
+               return;
+       if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
+               goto out;
+
+       smp_num_siblings = (ebx & 0xff0000) >> 16;
+
+       if (smp_num_siblings == 1) {
+               printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+       } else if (smp_num_siblings > 1) {
+
+               if (smp_num_siblings > NR_CPUS) {
+                       printk(KERN_WARNING "CPU: Unsupported number of "
+                              "siblings %d", smp_num_siblings);
+                       smp_num_siblings = 1;
+                       return;
+               }
+
+               index_msb = get_count_order(smp_num_siblings);
+               c->phys_proc_id = phys_pkg_id(index_msb);
+
+               smp_num_siblings = smp_num_siblings / c->x86_max_cores;
+
+               index_msb = get_count_order(smp_num_siblings);
+
+               core_bits = get_count_order(c->x86_max_cores);
+
+               c->cpu_core_id = phys_pkg_id(index_msb) &
+                                              ((1 << core_bits) - 1);
+       }
+out:
+       if ((c->x86_max_cores * smp_num_siblings) > 1) {
+               printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+                      c->phys_proc_id);
+               printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
+                      c->cpu_core_id);
+       }
+
+#endif
+}
+
+static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
+{
+       char *v = c->x86_vendor_id;
+       int i;
+       static int printed;
+
+       for (i = 0; i < X86_VENDOR_NUM; i++) {
+               if (cpu_devs[i]) {
+                       if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
+                           (cpu_devs[i]->c_ident[1] &&
+                           !strcmp(v, cpu_devs[i]->c_ident[1]))) {
+                               c->x86_vendor = i;
+                               this_cpu = cpu_devs[i];
+                               return;
+                       }
+               }
+       }
+       if (!printed) {
+               printed++;
+               printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
+               printk(KERN_ERR "CPU: Your system may be unstable.\n");
+       }
+       c->x86_vendor = X86_VENDOR_UNKNOWN;
+}
+
+static void __init early_cpu_support_print(void)
+{
+       int i,j;
+       struct cpu_dev *cpu_devx;
+
+       printk("KERNEL supported cpus:\n");
+       for (i = 0; i < X86_VENDOR_NUM; i++) {
+               cpu_devx = cpu_devs[i];
+               if (!cpu_devx)
+                       continue;
+               for (j = 0; j < 2; j++) {
+                       if (!cpu_devx->c_ident[j])
+                               continue;
+                       printk("  %s %s\n", cpu_devx->c_vendor,
+                               cpu_devx->c_ident[j]);
+               }
+       }
+}
+
+static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
+
+void __init early_cpu_init(void)
+{
+        struct cpu_vendor_dev *cvdev;
+
+        for (cvdev = __x86cpuvendor_start ;
+             cvdev < __x86cpuvendor_end   ;
+             cvdev++)
+                cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
+       early_cpu_support_print();
+       early_identify_cpu(&boot_cpu_data);
+}
+
+/* Do some early cpuid on the boot CPU to get some parameter that are
+   needed before check_bugs. Everything advanced is in identify_cpu
+   below. */
+static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
+{
+       u32 tfms, xlvl;
+
+       c->loops_per_jiffy = loops_per_jiffy;
+       c->x86_cache_size = -1;
+       c->x86_vendor = X86_VENDOR_UNKNOWN;
+       c->x86_model = c->x86_mask = 0; /* So far unknown... */
+       c->x86_vendor_id[0] = '\0'; /* Unset */
+       c->x86_model_id[0] = '\0';  /* Unset */
+       c->x86_clflush_size = 64;
+       c->x86_cache_alignment = c->x86_clflush_size;
+       c->x86_max_cores = 1;
+       c->x86_coreid_bits = 0;
+       c->extended_cpuid_level = 0;
+       memset(&c->x86_capability, 0, sizeof c->x86_capability);
+
+       /* Get vendor name */
+       cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
+             (unsigned int *)&c->x86_vendor_id[0],
+             (unsigned int *)&c->x86_vendor_id[8],
+             (unsigned int *)&c->x86_vendor_id[4]);
+
+       get_cpu_vendor(c);
+
+       /* Initialize the standard set of capabilities */
+       /* Note that the vendor-specific code below might override */
+
+       /* Intel-defined flags: level 0x00000001 */
+       if (c->cpuid_level >= 0x00000001) {
+               __u32 misc;
+               cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
+                     &c->x86_capability[0]);
+               c->x86 = (tfms >> 8) & 0xf;
+               c->x86_model = (tfms >> 4) & 0xf;
+               c->x86_mask = tfms & 0xf;
+               if (c->x86 == 0xf)
+                       c->x86 += (tfms >> 20) & 0xff;
+               if (c->x86 >= 0x6)
+                       c->x86_model += ((tfms >> 16) & 0xF) << 4;
+               if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
+                       c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+       } else {
+               /* Have CPUID level 0 only - unheard of */
+               c->x86 = 4;
+       }
+
+       c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xff;
+#ifdef CONFIG_SMP
+       c->phys_proc_id = c->initial_apicid;
+#endif
+       /* AMD-defined flags: level 0x80000001 */
+       xlvl = cpuid_eax(0x80000000);
+       c->extended_cpuid_level = xlvl;
+       if ((xlvl & 0xffff0000) == 0x80000000) {
+               if (xlvl >= 0x80000001) {
+                       c->x86_capability[1] = cpuid_edx(0x80000001);
+                       c->x86_capability[6] = cpuid_ecx(0x80000001);
+               }
+               if (xlvl >= 0x80000004)
+                       get_model_name(c); /* Default name */
+       }
+
+       /* Transmeta-defined flags: level 0x80860001 */
+       xlvl = cpuid_eax(0x80860000);
+       if ((xlvl & 0xffff0000) == 0x80860000) {
+               /* Don't set x86_cpuid_level here for now to not confuse. */
+               if (xlvl >= 0x80860001)
+                       c->x86_capability[2] = cpuid_edx(0x80860001);
+       }
+
+       c->extended_cpuid_level = cpuid_eax(0x80000000);
+       if (c->extended_cpuid_level >= 0x80000007)
+               c->x86_power = cpuid_edx(0x80000007);
+
+       if (c->extended_cpuid_level >= 0x80000008) {
+               u32 eax = cpuid_eax(0x80000008);
+
+               c->x86_virt_bits = (eax >> 8) & 0xff;
+               c->x86_phys_bits = eax & 0xff;
+       }
+
+       /* Assume all 64-bit CPUs support 32-bit syscall */
+       set_cpu_cap(c, X86_FEATURE_SYSCALL32);
+
+       if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
+           cpu_devs[c->x86_vendor]->c_early_init)
+               cpu_devs[c->x86_vendor]->c_early_init(c);
+
+       validate_pat_support(c);
+
+       /* early_param could clear that, but recall get it set again */
+       if (disable_apic)
+               clear_cpu_cap(c, X86_FEATURE_APIC);
+}
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+{
+       int i;
+
+       early_identify_cpu(c);
+
+       init_scattered_cpuid_features(c);
+
+       c->apicid = phys_pkg_id(0);
+
+       /*
+        * Vendor-specific initialization.  In this section we
+        * canonicalize the feature flags, meaning if there are
+        * features a certain CPU supports which CPUID doesn't
+        * tell us, CPUID claiming incorrect flags, or other bugs,
+        * we handle them here.
+        *
+        * At the end of this section, c->x86_capability better
+        * indicate the features this CPU genuinely supports!
+        */
+       if (this_cpu->c_init)
+               this_cpu->c_init(c);
+
+       detect_ht(c);
+
+       /*
+        * On SMP, boot_cpu_data holds the common feature set between
+        * all CPUs; so make sure that we indicate which features are
+        * common between the CPUs.  The first time this routine gets
+        * executed, c == &boot_cpu_data.
+        */
+       if (c != &boot_cpu_data) {
+               /* AND the already accumulated flags with these */
+               for (i = 0; i < NCAPINTS; i++)
+                       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
+       mcheck_init(c);
+#endif
+       select_idle_routine(c);
+
+#ifdef CONFIG_NUMA
+       numa_add_cpu(smp_processor_id());
+#endif
+
+}
+
+void __cpuinit identify_boot_cpu(void)
+{
+       identify_cpu(&boot_cpu_data);
+}
+
+void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
+{
+       BUG_ON(c == &boot_cpu_data);
+       identify_cpu(c);
+       mtrr_ap_init();
+}
+
+static __init int setup_noclflush(char *arg)
+{
+       setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
+       return 1;
+}
+__setup("noclflush", setup_noclflush);
+
+void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
+{
+       if (c->x86_model_id[0])
+               printk(KERN_CONT "%s", c->x86_model_id);
+
+       if (c->x86_mask || c->cpuid_level >= 0)
+               printk(KERN_CONT " stepping %02x\n", c->x86_mask);
+       else
+               printk(KERN_CONT "\n");
+}
+
+static __init int setup_disablecpuid(char *arg)
+{
+       int bit;
+       if (get_option(&arg, &bit) && bit < NCAPINTS*32)
+               setup_clear_cpu_cap(bit);
+       else
+               return 0;
+       return 1;
+}
+__setup("clearcpuid=", setup_disablecpuid);
+
+cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
+
+struct x8664_pda **_cpu_pda __read_mostly;
+EXPORT_SYMBOL(_cpu_pda);
+
+struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
+
+char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss;
+
+unsigned long __supported_pte_mask __read_mostly = ~0UL;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
+
+static int do_not_nx __cpuinitdata;
+
+/* noexec=on|off
+Control non executable mappings for 64bit 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;
+               do_not_nx = 0;
+       } else if (!strncmp(str, "off", 3)) {
+               do_not_nx = 1;
+               __supported_pte_mask &= ~_PAGE_NX;
+       }
+       return 0;
+}
+early_param("noexec", nonx_setup);
+
+int force_personality32;
+
+/* noexec32=on|off
+Control non executable heap for 32bit processes.
+To control the stack too use noexec=off
+
+on     PROT_READ does not imply PROT_EXEC for 32bit processes (default)
+off    PROT_READ implies PROT_EXEC
+*/
+static int __init nonx32_setup(char *str)
+{
+       if (!strcmp(str, "on"))
+               force_personality32 &= ~READ_IMPLIES_EXEC;
+       else if (!strcmp(str, "off"))
+               force_personality32 |= READ_IMPLIES_EXEC;
+       return 1;
+}
+__setup("noexec32=", nonx32_setup);
+
+void pda_init(int cpu)
+{
+       struct x8664_pda *pda = cpu_pda(cpu);
+
+       /* Setup up data that may be needed in __get_free_pages early */
+       loadsegment(fs, 0);
+       loadsegment(gs, 0);
+       /* Memory clobbers used to order PDA accessed */
+       mb();
+       wrmsrl(MSR_GS_BASE, pda);
+       mb();
+
+       pda->cpunumber = cpu;
+       pda->irqcount = -1;
+       pda->kernelstack = (unsigned long)stack_thread_info() -
+                                PDA_STACKOFFSET + THREAD_SIZE;
+       pda->active_mm = &init_mm;
+       pda->mmu_state = 0;
+
+       if (cpu == 0) {
+               /* others are initialized in smpboot.c */
+               pda->pcurrent = &init_task;
+               pda->irqstackptr = boot_cpu_stack;
+       } else {
+               pda->irqstackptr = (char *)
+                       __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
+               if (!pda->irqstackptr)
+                       panic("cannot allocate irqstack for cpu %d", cpu);
+
+               if (pda->nodenumber == 0 && cpu_to_node(cpu) != NUMA_NO_NODE)
+                       pda->nodenumber = cpu_to_node(cpu);
+       }
+
+       pda->irqstackptr += IRQSTACKSIZE-64;
+}
+
+char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ +
+                          DEBUG_STKSZ]
+__attribute__((section(".bss.page_aligned")));
+
+extern asmlinkage void ignore_sysret(void);
+
+/* May not be marked __init: used by software suspend */
+void syscall_init(void)
+{
+       /*
+        * LSTAR and STAR live in a bit strange symbiosis.
+        * They both write to the same internal register. STAR allows to
+        * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
+        */
+       wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32);
+       wrmsrl(MSR_LSTAR, system_call);
+       wrmsrl(MSR_CSTAR, ignore_sysret);
+
+#ifdef CONFIG_IA32_EMULATION
+       syscall32_cpu_init();
+#endif
+
+       /* Flags to clear on syscall */
+       wrmsrl(MSR_SYSCALL_MASK,
+              X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
+}
+
+void __cpuinit check_efer(void)
+{
+       unsigned long efer;
+
+       rdmsrl(MSR_EFER, efer);
+       if (!(efer & EFER_NX) || do_not_nx)
+               __supported_pte_mask &= ~_PAGE_NX;
+}
+
+unsigned long kernel_eflags;
+
+/*
+ * Copies of the original ist values from the tss are only accessed during
+ * debugging, no special alignment required.
+ */
+DEFINE_PER_CPU(struct orig_ist, orig_ist);
+
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+ * and IDT. We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ * A lot of state is already set up in PDA init.
+ */
+void __cpuinit cpu_init(void)
+{
+       int cpu = stack_smp_processor_id();
+       struct tss_struct *t = &per_cpu(init_tss, cpu);
+       struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
+       unsigned long v;
+       char *estacks = NULL;
+       struct task_struct *me;
+       int i;
+
+       /* CPU 0 is initialised in head64.c */
+       if (cpu != 0)
+               pda_init(cpu);
+       else
+               estacks = boot_exception_stacks;
+
+       me = current;
+
+       if (cpu_test_and_set(cpu, cpu_initialized))
+               panic("CPU#%d already initialized!\n", cpu);
+
+       printk(KERN_INFO "Initializing CPU#%d\n", cpu);
+
+       clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+
+       /*
+        * Initialize the per-CPU GDT with the boot GDT,
+        * and set up the GDT descriptor:
+        */
+
+       switch_to_new_gdt();
+       load_idt((const struct desc_ptr *)&idt_descr);
+
+       memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
+       syscall_init();
+
+       wrmsrl(MSR_FS_BASE, 0);
+       wrmsrl(MSR_KERNEL_GS_BASE, 0);
+       barrier();
+
+       check_efer();
+
+       /*
+        * set up and load the per-CPU TSS
+        */
+       for (v = 0; v < N_EXCEPTION_STACKS; v++) {
+               static const unsigned int order[N_EXCEPTION_STACKS] = {
+                       [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
+                       [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
+               };
+               if (cpu) {
+                       estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
+                       if (!estacks)
+                               panic("Cannot allocate exception stack %ld %d\n",
+                                     v, cpu);
+               }
+               estacks += PAGE_SIZE << order[v];
+               orig_ist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks;
+       }
+
+       t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
+       /*
+        * <= is required because the CPU will access up to
+        * 8 bits beyond the end of the IO permission bitmap.
+        */
+       for (i = 0; i <= IO_BITMAP_LONGS; i++)
+               t->io_bitmap[i] = ~0UL;
+
+       atomic_inc(&init_mm.mm_count);
+       me->active_mm = &init_mm;
+       if (me->mm)
+               BUG();
+       enter_lazy_tlb(&init_mm, me);
+
+       load_sp0(t, &current->thread);
+       set_tss_desc(cpu, t);
+       load_TR_desc();
+       load_LDT(&init_mm.context);
+
+#ifdef CONFIG_KGDB
+       /*
+        * If the kgdb is connected no debug regs should be altered.  This
+        * is only applicable when KGDB and a KGDB I/O module are built
+        * into the kernel and you are using early debugging with
+        * kgdbwait. KGDB will control the kernel HW breakpoint registers.
+        */
+       if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
+               arch_kgdb_ops.correct_hw_break();
+       else {
+#endif
+       /*
+        * Clear all 6 debug registers:
+        */
+
+       set_debugreg(0UL, 0);
+       set_debugreg(0UL, 1);
+       set_debugreg(0UL, 2);
+       set_debugreg(0UL, 3);
+       set_debugreg(0UL, 6);
+       set_debugreg(0UL, 7);
+#ifdef CONFIG_KGDB
+       /* If the kgdb is connected no debug regs should be altered. */
+       }
+#endif
+
+       fpu_init();
+
+       raw_local_save_flags(kernel_eflags);
+
+       if (is_uv_system())
+               uv_cpu_init();
+}
index 783691b2a7381648bbc03ccf98842b0fcad6df22..4d894e8565feb6ad22b103f9c87ae51641ca0eda 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef ARCH_X86_CPU_H
+
+#define ARCH_X86_CPU_H
 
 struct cpu_model_info {
        int vendor;
@@ -36,3 +39,5 @@ extern struct cpu_vendor_dev __x86cpuvendor_start[], __x86cpuvendor_end[];
 
 extern int get_model_name(struct cpuinfo_x86 *c);
 extern void display_cacheinfo(struct cpuinfo_x86 *c);
+
+#endif
index f03e9153618e52d68f2730f7e7a07e3d9fd71c2b..965ea52767ac65f5059673a3448764103a0e8543 100644 (file)
 #define NFORCE2_SAFE_DISTANCE 50
 
 /* Delay in ms between FSB changes */
-//#define NFORCE2_DELAY 10
+/* #define NFORCE2_DELAY 10 */
 
-/* nforce2_chipset:
+/*
+ * nforce2_chipset:
  * FSB is changed using the chipset
  */
 static struct pci_dev *nforce2_chipset_dev;
@@ -36,13 +37,13 @@ static struct pci_dev *nforce2_chipset_dev;
 /* fid:
  * multiplier * 10
  */
-static int fid = 0;
+static int fid;
 
 /* min_fsb, max_fsb:
  * minimum and maximum FSB (= FSB at boot time)
  */
-static int min_fsb = 0;
-static int max_fsb = 0;
+static int min_fsb;
+static int max_fsb;
 
 MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
 MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver");
@@ -53,7 +54,7 @@ module_param(min_fsb, int, 0444);
 
 MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
 MODULE_PARM_DESC(min_fsb,
-                 "Minimum FSB to use, if not defined: current FSB - 50");
+               "Minimum FSB to use, if not defined: current FSB - 50");
 
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg)
 
@@ -139,7 +140,7 @@ static unsigned int nforce2_fsb_read(int bootfsb)
 
        /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
        nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
-                                               0x01EF,PCI_ANY_ID,PCI_ANY_ID,NULL);
+                                               0x01EF, PCI_ANY_ID, PCI_ANY_ID, NULL);
        if (!nforce2_sub5)
                return 0;
 
@@ -147,13 +148,13 @@ static unsigned int nforce2_fsb_read(int bootfsb)
        fsb /= 1000000;
 
        /* Check if PLL register is already set */
-       pci_read_config_byte(nforce2_chipset_dev,NFORCE2_PLLENABLE, (u8 *)&temp);
+       pci_read_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
 
-       if(bootfsb || !temp)
+       if (bootfsb || !temp)
                return fsb;
-               
+
        /* Use PLL register FSB value */
-       pci_read_config_dword(nforce2_chipset_dev,NFORCE2_PLLREG, &temp);
+       pci_read_config_dword(nforce2_chipset_dev, NFORCE2_PLLREG, &temp);
        fsb = nforce2_calc_fsb(temp);
 
        return fsb;
@@ -184,7 +185,7 @@ static int nforce2_set_fsb(unsigned int fsb)
        }
 
        /* First write? Then set actual value */
-       pci_read_config_byte(nforce2_chipset_dev,NFORCE2_PLLENABLE, (u8 *)&temp);
+       pci_read_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
        if (!temp) {
                pll = nforce2_calc_pll(tfsb);
 
@@ -210,7 +211,8 @@ static int nforce2_set_fsb(unsigned int fsb)
                        tfsb--;
 
                /* Calculate the PLL reg. value */
-               if ((pll = nforce2_calc_pll(tfsb)) == -1)
+               pll = nforce2_calc_pll(tfsb);
+               if (pll == -1)
                        return -EINVAL;
 
                nforce2_write_pll(pll);
@@ -249,7 +251,7 @@ static unsigned int nforce2_get(unsigned int cpu)
 static int nforce2_target(struct cpufreq_policy *policy,
                          unsigned int target_freq, unsigned int relation)
 {
-//        unsigned long         flags;
+/*        unsigned long         flags; */
        struct cpufreq_freqs freqs;
        unsigned int target_fsb;
 
@@ -271,17 +273,17 @@ static int nforce2_target(struct cpufreq_policy *policy,
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
        /* Disable IRQs */
-       //local_irq_save(flags);
+       /* local_irq_save(flags); */
 
        if (nforce2_set_fsb(target_fsb) < 0)
                printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n",
-                       target_fsb);
+                       target_fsb);
        else
                dprintk("Changed FSB successfully to %d\n",
-                       target_fsb);
+                       target_fsb);
 
        /* Enable IRQs */
-       //local_irq_restore(flags);
+       /* local_irq_restore(flags); */
 
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
@@ -302,8 +304,8 @@ static int nforce2_verify(struct cpufreq_policy *policy)
                policy->max = (fsb_pol_max + 1) * fid * 100;
 
        cpufreq_verify_within_limits(policy,
-                                     policy->cpuinfo.min_freq,
-                                     policy->cpuinfo.max_freq);
+                                    policy->cpuinfo.min_freq,
+                                    policy->cpuinfo.max_freq);
        return 0;
 }
 
@@ -347,7 +349,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
        /* Set maximum FSB to FSB at boot time */
        max_fsb = nforce2_fsb_read(1);
 
-       if(!max_fsb)
+       if (!max_fsb)
                return -EIO;
 
        if (!min_fsb)
index fe9224c51d37ee1ca4cd36d6e7265e8124059012..70609efdf1da3ae7fea3a311ffbb1639e3f5675e 100644 (file)
@@ -226,6 +226,10 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
 
        if (cpu_has_bts)
                ds_init_intel(c);
+
+#ifdef CONFIG_X86_NUMAQ
+       numaq_tsc_disable();
+#endif
 }
 
 static unsigned int __cpuinit intel_size_cache(struct cpuinfo_x86 *c, unsigned int size)
diff --git a/arch/x86/kernel/cpu/intel_64.c b/arch/x86/kernel/cpu/intel_64.c
new file mode 100644 (file)
index 0000000..1019c58
--- /dev/null
@@ -0,0 +1,95 @@
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/topology.h>
+#include <asm/numa_64.h>
+
+#include "cpu.h"
+
+static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
+{
+       if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
+           (c->x86 == 0x6 && c->x86_model >= 0x0e))
+               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
+
+       set_cpu_cap(c, X86_FEATURE_SYSENTER32);
+}
+
+/*
+ * find out the number of processor cores on the die
+ */
+static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
+{
+       unsigned int eax, t;
+
+       if (c->cpuid_level < 4)
+               return 1;
+
+       cpuid_count(4, 0, &eax, &t, &t, &t);
+
+       if (eax & 0x1f)
+               return ((eax >> 26) + 1);
+       else
+               return 1;
+}
+
+static void __cpuinit srat_detect_node(void)
+{
+#ifdef CONFIG_NUMA
+       unsigned node;
+       int cpu = smp_processor_id();
+       int apicid = hard_smp_processor_id();
+
+       /* Don't do the funky fallback heuristics the AMD version employs
+          for now. */
+       node = apicid_to_node[apicid];
+       if (node == NUMA_NO_NODE || !node_online(node))
+               node = first_node(node_online_map);
+       numa_set_node(cpu, node);
+
+       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
+#endif
+}
+
+static void __cpuinit init_intel(struct cpuinfo_x86 *c)
+{
+       init_intel_cacheinfo(c);
+       if (c->cpuid_level > 9) {
+               unsigned eax = cpuid_eax(10);
+               /* Check for version and the number of counters */
+               if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
+                       set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
+       }
+
+       if (cpu_has_ds) {
+               unsigned int l1, l2;
+               rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
+               if (!(l1 & (1<<11)))
+                       set_cpu_cap(c, X86_FEATURE_BTS);
+               if (!(l1 & (1<<12)))
+                       set_cpu_cap(c, X86_FEATURE_PEBS);
+       }
+
+
+       if (cpu_has_bts)
+               ds_init_intel(c);
+
+       if (c->x86 == 15)
+               c->x86_cache_alignment = c->x86_clflush_size * 2;
+       if (c->x86 == 6)
+               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
+       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+       c->x86_max_cores = intel_num_cpu_cores(c);
+
+       srat_detect_node();
+}
+
+static struct cpu_dev intel_cpu_dev __cpuinitdata = {
+       .c_vendor       = "Intel",
+       .c_ident        = { "GenuineIntel" },
+       .c_early_init   = early_init_intel,
+       .c_init         = init_intel,
+};
+cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
+
index 26d615dcb1498ed7664b2483e3a68e74abc5ee71..2c8afafa18e860ff98fafb243f2ba7964496c42d 100644 (file)
@@ -62,6 +62,7 @@ static struct _cache_table cache_table[] __cpuinitdata =
        { 0x4b, LVL_3,      8192 },     /* 16-way set assoc, 64 byte line size */
        { 0x4c, LVL_3,     12288 },     /* 12-way set assoc, 64 byte line size */
        { 0x4d, LVL_3,     16384 },     /* 16-way set assoc, 64 byte line size */
+       { 0x4e, LVL_2,      6144 },     /* 24-way set assoc, 64 byte line size */
        { 0x60, LVL_1_DATA, 16 },       /* 8-way set assoc, sectored cache, 64 byte line size */
        { 0x66, LVL_1_DATA, 8 },        /* 4-way set assoc, sectored cache, 64 byte line size */
        { 0x67, LVL_1_DATA, 16 },       /* 4-way set assoc, sectored cache, 64 byte line size */
index e633c9c2b764c3ec7829420b06b6ece9c459d455..f390c9f66351ae850ca169b5e399b32d555bd266 100644 (file)
@@ -9,23 +9,23 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 
-#include <asm/processor.h> 
+#include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/msr.h>
 
 #include "mce.h"
 
 /* Machine Check Handler For AMD Athlon/Duron */
-static void k7_machine_check(struct pt_regs * regs, long error_code)
+static void k7_machine_check(struct pt_regs *regs, long error_code)
 {
-       int recover=1;
+       int recover = 1;
        u32 alow, ahigh, high, low;
        u32 mcgstl, mcgsth;
        int i;
 
-       rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
+       rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
        if (mcgstl & (1<<0))    /* Recoverable ? */
-               recover=0;
+               recover = 0;
 
        printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
                smp_processor_id(), mcgsth, mcgstl);
@@ -60,12 +60,12 @@ static void k7_machine_check(struct pt_regs * regs, long error_code)
        }
 
        if (recover&2)
-               panic ("CPU context corrupt");
+               panic("CPU context corrupt");
        if (recover&1)
-               panic ("Unable to continue");
-       printk (KERN_EMERG "Attempting to continue.\n");
+               panic("Unable to continue");
+       printk(KERN_EMERG "Attempting to continue.\n");
        mcgstl &= ~(1<<2);
-       wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
+       wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
 
@@ -81,25 +81,25 @@ void amd_mcheck_init(struct cpuinfo_x86 *c)
        machine_check_vector = k7_machine_check;
        wmb();
 
-       printk (KERN_INFO "Intel machine check architecture supported.\n");
-       rdmsr (MSR_IA32_MCG_CAP, l, h);
+       printk(KERN_INFO "Intel machine check architecture supported.\n");
+       rdmsr(MSR_IA32_MCG_CAP, l, h);
        if (l & (1<<8)) /* Control register present ? */
-               wrmsr (MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+               wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
        nr_mce_banks = l & 0xff;
 
        /* Clear status for MC index 0 separately, we don't touch CTL,
         * as some K7 Athlons cause spurious MCEs when its enabled. */
        if (boot_cpu_data.x86 == 6) {
-               wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
+               wrmsr(MSR_IA32_MC0_STATUS, 0x0, 0x0);
                i = 1;
        } else
                i = 0;
-       for (; i<nr_mce_banks; i++) {
-               wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
-               wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+       for (; i < nr_mce_banks; i++) {
+               wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+               wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
        }
 
-       set_in_cr4 (X86_CR4_MCE);
-       printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
+       set_in_cr4(X86_CR4_MCE);
+       printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
                smp_processor_id());
 }
index e07e8c068ae00c464cdbf828cfbc8c67aaf76202..501ca1cea27d96c33711029219345a73475de274 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/idle.h>
 
 #define MISC_MCELOG_MINOR 227
-#define NR_BANKS 6
+#define NR_SYSFS_BANKS 6
 
 atomic_t mce_entry;
 
@@ -46,7 +46,7 @@ static int mce_dont_init;
  */
 static int tolerant = 1;
 static int banks;
-static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
+static unsigned long bank[NR_SYSFS_BANKS] = { [0 ... NR_SYSFS_BANKS-1] = ~0UL };
 static unsigned long notify_user;
 static int rip_msr;
 static int mce_bootlog = -1;
@@ -209,7 +209,7 @@ void do_machine_check(struct pt_regs * regs, long error_code)
        barrier();
 
        for (i = 0; i < banks; i++) {
-               if (!bank[i])
+               if (i < NR_SYSFS_BANKS && !bank[i])
                        continue;
 
                m.misc = 0;
@@ -444,9 +444,10 @@ static void mce_init(void *dummy)
 
        rdmsrl(MSR_IA32_MCG_CAP, cap);
        banks = cap & 0xff;
-       if (banks > NR_BANKS) {
-               printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
-               banks = NR_BANKS;
+       if (banks > MCE_EXTENDED_BANK) {
+               banks = MCE_EXTENDED_BANK;
+               printk(KERN_INFO "MCE: warning: using only %d banks\n",
+                      MCE_EXTENDED_BANK);
        }
        /* Use accurate RIP reporting if available. */
        if ((cap & (1<<9)) && ((cap >> 16) & 0xff) >= 9)
@@ -462,7 +463,11 @@ static void mce_init(void *dummy)
                wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 
        for (i = 0; i < banks; i++) {
-               wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
+               if (i < NR_SYSFS_BANKS)
+                       wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
+               else
+                       wrmsrl(MSR_IA32_MC0_CTL+4*i, ~0UL);
+
                wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
        }
 }
@@ -766,7 +771,10 @@ DEFINE_PER_CPU(struct sys_device, device_mce);
        }                                                               \
        static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
 
-/* TBD should generate these dynamically based on number of available banks */
+/*
+ * TBD should generate these dynamically based on number of available banks.
+ * Have only 6 contol banks in /sysfs until then.
+ */
 ACCESSOR(bank0ctl,bank[0],mce_restart())
 ACCESSOR(bank1ctl,bank[1],mce_restart())
 ACCESSOR(bank2ctl,bank[2],mce_restart())
index cb03345554a5cfe0153ea8ad6ef0d739fc8b1583..eef001ad3bdee23a5a5585ce75dd7be4378f40ff 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 
-#include <asm/processor.h> 
+#include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/msr.h>
 #include <asm/apic.h>
@@ -32,12 +32,12 @@ struct intel_mce_extended_msrs {
        /* u32 *reserved[]; */
 };
 
-static int mce_num_extended_msrs = 0;
+static int mce_num_extended_msrs;
 
 
 #ifdef CONFIG_X86_MCE_P4THERMAL
 static void unexpected_thermal_interrupt(struct pt_regs *regs)
-{      
+{
        printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n",
                        smp_processor_id());
        add_taint(TAINT_MACHINE_CHECK);
@@ -83,7 +83,7 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
         * be some SMM goo which handles it, so we can't even put a handler
         * since it might be delivered via SMI already -zwanem.
         */
-       rdmsr (MSR_IA32_MISC_ENABLE, l, h);
+       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
        h = apic_read(APIC_LVTTHMR);
        if ((l & (1<<3)) && (h & APIC_DM_SMI)) {
                printk(KERN_DEBUG "CPU%d: Thermal monitoring handled by SMI\n",
@@ -91,7 +91,7 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
                return; /* -EBUSY */
        }
 
-       /* check whether a vector already exists, temporarily masked? */        
+       /* check whether a vector already exists, temporarily masked? */
        if (h & APIC_VECTOR_MASK) {
                printk(KERN_DEBUG "CPU%d: Thermal LVT vector (%#x) already "
                                "installed\n",
@@ -104,18 +104,18 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
        h |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */
        apic_write_around(APIC_LVTTHMR, h);
 
-       rdmsr (MSR_IA32_THERM_INTERRUPT, l, h);
-       wrmsr (MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
+       rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
+       wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
 
        /* ok we're good to go... */
        vendor_thermal_interrupt = intel_thermal_interrupt;
-       
-       rdmsr (MSR_IA32_MISC_ENABLE, l, h);
-       wrmsr (MSR_IA32_MISC_ENABLE, l | (1<<3), h);
 
-       l = apic_read (APIC_LVTTHMR);
-       apic_write_around (APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-       printk (KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu);
+       rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+       wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+
+       l = apic_read(APIC_LVTTHMR);
+       apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+       printk(KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu);
 
        /* enable thermal throttle processing */
        atomic_set(&therm_throt_en, 1);
@@ -129,28 +129,28 @@ static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
 {
        u32 h;
 
-       rdmsr (MSR_IA32_MCG_EAX, r->eax, h);
-       rdmsr (MSR_IA32_MCG_EBX, r->ebx, h);
-       rdmsr (MSR_IA32_MCG_ECX, r->ecx, h);
-       rdmsr (MSR_IA32_MCG_EDX, r->edx, h);
-       rdmsr (MSR_IA32_MCG_ESI, r->esi, h);
-       rdmsr (MSR_IA32_MCG_EDI, r->edi, h);
-       rdmsr (MSR_IA32_MCG_EBP, r->ebp, h);
-       rdmsr (MSR_IA32_MCG_ESP, r->esp, h);
-       rdmsr (MSR_IA32_MCG_EFLAGS, r->eflags, h);
-       rdmsr (MSR_IA32_MCG_EIP, r->eip, h);
+       rdmsr(MSR_IA32_MCG_EAX, r->eax, h);
+       rdmsr(MSR_IA32_MCG_EBX, r->ebx, h);
+       rdmsr(MSR_IA32_MCG_ECX, r->ecx, h);
+       rdmsr(MSR_IA32_MCG_EDX, r->edx, h);
+       rdmsr(MSR_IA32_MCG_ESI, r->esi, h);
+       rdmsr(MSR_IA32_MCG_EDI, r->edi, h);
+       rdmsr(MSR_IA32_MCG_EBP, r->ebp, h);
+       rdmsr(MSR_IA32_MCG_ESP, r->esp, h);
+       rdmsr(MSR_IA32_MCG_EFLAGS, r->eflags, h);
+       rdmsr(MSR_IA32_MCG_EIP, r->eip, h);
 }
 
-static void intel_machine_check(struct pt_regs * regs, long error_code)
+static void intel_machine_check(struct pt_regs *regs, long error_code)
 {
-       int recover=1;
+       int recover = 1;
        u32 alow, ahigh, high, low;
        u32 mcgstl, mcgsth;
        int i;
 
-       rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
+       rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
        if (mcgstl & (1<<0))    /* Recoverable ? */
-               recover=0;
+               recover = 0;
 
        printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
                smp_processor_id(), mcgsth, mcgstl);
@@ -191,20 +191,20 @@ static void intel_machine_check(struct pt_regs * regs, long error_code)
        }
 
        if (recover & 2)
-               panic ("CPU context corrupt");
+               panic("CPU context corrupt");
        if (recover & 1)
-               panic ("Unable to continue");
+               panic("Unable to continue");
 
        printk(KERN_EMERG "Attempting to continue.\n");
-       /* 
-        * Do not clear the MSR_IA32_MCi_STATUS if the error is not 
+       /*
+        * Do not clear the MSR_IA32_MCi_STATUS if the error is not
         * recoverable/continuable.This will allow BIOS to look at the MSRs
         * for errors if the OS could not log the error.
         */
-       for (i=0; i<nr_mce_banks; i++) {
+       for (i = 0; i < nr_mce_banks; i++) {
                u32 msr;
                msr = MSR_IA32_MC0_STATUS+i*4;
-               rdmsr (msr, low, high);
+               rdmsr(msr, low, high);
                if (high&(1<<31)) {
                        /* Clear it */
                        wrmsr(msr, 0UL, 0UL);
@@ -214,7 +214,7 @@ static void intel_machine_check(struct pt_regs * regs, long error_code)
                }
        }
        mcgstl &= ~(1<<2);
-       wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
+       wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 }
 
 
@@ -222,30 +222,30 @@ void intel_p4_mcheck_init(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int i;
-       
+
        machine_check_vector = intel_machine_check;
        wmb();
 
-       printk (KERN_INFO "Intel machine check architecture supported.\n");
-       rdmsr (MSR_IA32_MCG_CAP, l, h);
+       printk(KERN_INFO "Intel machine check architecture supported.\n");
+       rdmsr(MSR_IA32_MCG_CAP, l, h);
        if (l & (1<<8)) /* Control register present ? */
-               wrmsr (MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+               wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
        nr_mce_banks = l & 0xff;
 
-       for (i=0; i<nr_mce_banks; i++) {
-               wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
-               wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+       for (i = 0; i < nr_mce_banks; i++) {
+               wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+               wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
        }
 
-       set_in_cr4 (X86_CR4_MCE);
-       printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
+       set_in_cr4(X86_CR4_MCE);
+       printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
                smp_processor_id());
 
        /* Check for P4/Xeon extended MCE MSRs */
-       rdmsr (MSR_IA32_MCG_CAP, l, h);
+       rdmsr(MSR_IA32_MCG_CAP, l, h);
        if (l & (1<<9)) {/* MCG_EXT_P */
                mce_num_extended_msrs = (l >> 16) & 0xff;
-               printk (KERN_INFO "CPU%d: Intel P4/Xeon Extended MCE MSRs (%d)"
+               printk(KERN_INFO "CPU%d: Intel P4/Xeon Extended MCE MSRs (%d)"
                                " available\n",
                        smp_processor_id(), mce_num_extended_msrs);
 
index 5d241ce94a44f4f5b0fceb7a7a8292e08b6d9b08..509bd3d9eacd28da737ade7a365f1a17acf71a11 100644 (file)
@@ -37,7 +37,7 @@ static struct fixed_range_block fixed_range_blocks[] = {
 static unsigned long smp_changes_mask;
 static struct mtrr_state mtrr_state = {};
 static int mtrr_state_set;
-static u64 tom2;
+u64 mtrr_tom2;
 
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "mtrr."
@@ -139,8 +139,8 @@ u8 mtrr_type_lookup(u64 start, u64 end)
                }
        }
 
-       if (tom2) {
-               if (start >= (1ULL<<32) && (end < tom2))
+       if (mtrr_tom2) {
+               if (start >= (1ULL<<32) && (end < mtrr_tom2))
                        return MTRR_TYPE_WRBACK;
        }
 
@@ -158,6 +158,20 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
        rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
 }
 
+/*  fill the MSR pair relating to a var range  */
+void fill_mtrr_var_range(unsigned int index,
+               u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi)
+{
+       struct mtrr_var_range *vr;
+
+       vr = mtrr_state.var_ranges;
+
+       vr[index].base_lo = base_lo;
+       vr[index].base_hi = base_hi;
+       vr[index].mask_lo = mask_lo;
+       vr[index].mask_hi = mask_hi;
+}
+
 static void
 get_fixed_ranges(mtrr_type * frs)
 {
@@ -213,13 +227,13 @@ void __init get_mtrr_state(void)
        mtrr_state.enabled = (lo & 0xc00) >> 10;
 
        if (amd_special_default_mtrr()) {
-               unsigned lo, hi;
+               unsigned low, high;
                /* TOP_MEM2 */
-               rdmsr(MSR_K8_TOP_MEM2, lo, hi);
-               tom2 = hi;
-               tom2 <<= 32;
-               tom2 |= lo;
-               tom2 &= 0xffffff8000000ULL;
+               rdmsr(MSR_K8_TOP_MEM2, low, high);
+               mtrr_tom2 = high;
+               mtrr_tom2 <<= 32;
+               mtrr_tom2 |= low;
+               mtrr_tom2 &= 0xffffff800000ULL;
        }
        if (mtrr_show) {
                int high_width;
@@ -251,9 +265,9 @@ void __init get_mtrr_state(void)
                        else
                                printk(KERN_INFO "MTRR %u disabled\n", i);
                }
-               if (tom2) {
+               if (mtrr_tom2) {
                        printk(KERN_INFO "TOM2: %016llx aka %lldM\n",
-                                         tom2, tom2>>20);
+                                         mtrr_tom2, mtrr_tom2>>20);
                }
        }
        mtrr_state_set = 1;
@@ -328,7 +342,7 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
 
        if (lo != msrwords[0] || hi != msrwords[1]) {
                if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-                   boot_cpu_data.x86 == 15 &&
+                   (boot_cpu_data.x86 >= 0x0f && boot_cpu_data.x86 <= 0x11) &&
                    ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK))
                        k8_enable_fixed_iorrs();
                mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
index 6a1e278d93230de4da44549cf537a33b5b3ff441..105afe12beb0730f1c5fbb02443adae516794a08 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/smp.h>
 #include <linux/cpu.h>
 #include <linux/mutex.h>
+#include <linux/sort.h>
 
 #include <asm/e820.h>
 #include <asm/mtrr.h>
@@ -609,6 +610,787 @@ static struct sysdev_driver mtrr_sysdev_driver = {
        .resume         = mtrr_restore,
 };
 
+/* should be related to MTRR_VAR_RANGES nums */
+#define RANGE_NUM 256
+
+struct res_range {
+       unsigned long start;
+       unsigned long end;
+};
+
+static int __init
+add_range(struct res_range *range, int nr_range, unsigned long start,
+                             unsigned long end)
+{
+       /* out of slots */
+       if (nr_range >= RANGE_NUM)
+               return nr_range;
+
+       range[nr_range].start = start;
+       range[nr_range].end = end;
+
+       nr_range++;
+
+       return nr_range;
+}
+
+static int __init
+add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
+                             unsigned long end)
+{
+       int i;
+
+       /* try to merge it with old one */
+       for (i = 0; i < nr_range; i++) {
+               unsigned long final_start, final_end;
+               unsigned long common_start, common_end;
+
+               if (!range[i].end)
+                       continue;
+
+               common_start = max(range[i].start, start);
+               common_end = min(range[i].end, end);
+               if (common_start > common_end + 1)
+                       continue;
+
+               final_start = min(range[i].start, start);
+               final_end = max(range[i].end, end);
+
+               range[i].start = final_start;
+               range[i].end =  final_end;
+               return nr_range;
+       }
+
+       /* need to add that */
+       return add_range(range, nr_range, start, end);
+}
+
+static void __init
+subtract_range(struct res_range *range, unsigned long start, unsigned long end)
+{
+       int i, j;
+
+       for (j = 0; j < RANGE_NUM; j++) {
+               if (!range[j].end)
+                       continue;
+
+               if (start <= range[j].start && end >= range[j].end) {
+                       range[j].start = 0;
+                       range[j].end = 0;
+                       continue;
+               }
+
+               if (start <= range[j].start && end < range[j].end &&
+                   range[j].start < end + 1) {
+                       range[j].start = end + 1;
+                       continue;
+               }
+
+
+               if (start > range[j].start && end >= range[j].end &&
+                   range[j].end > start - 1) {
+                       range[j].end = start - 1;
+                       continue;
+               }
+
+               if (start > range[j].start && end < range[j].end) {
+                       /* find the new spare */
+                       for (i = 0; i < RANGE_NUM; i++) {
+                               if (range[i].end == 0)
+                                       break;
+                       }
+                       if (i < RANGE_NUM) {
+                               range[i].end = range[j].end;
+                               range[i].start = end + 1;
+                       } else {
+                               printk(KERN_ERR "run of slot in ranges\n");
+                       }
+                       range[j].end = start - 1;
+                       continue;
+               }
+       }
+}
+
+static int __init cmp_range(const void *x1, const void *x2)
+{
+       const struct res_range *r1 = x1;
+       const struct res_range *r2 = x2;
+       long start1, start2;
+
+       start1 = r1->start;
+       start2 = r2->start;
+
+       return start1 - start2;
+}
+
+struct var_mtrr_range_state {
+       unsigned long base_pfn;
+       unsigned long size_pfn;
+       mtrr_type type;
+};
+
+struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
+static int __initdata debug_print;
+
+static int __init
+x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
+                      unsigned long extra_remove_base,
+                      unsigned long extra_remove_size)
+{
+       unsigned long i, base, size;
+       mtrr_type type;
+
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_WRBACK)
+                       continue;
+               base = range_state[i].base_pfn;
+               size = range_state[i].size_pfn;
+               nr_range = add_range_with_merge(range, nr_range, base,
+                                               base + size - 1);
+       }
+       if (debug_print) {
+               printk(KERN_DEBUG "After WB checking\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* take out UC ranges */
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_UNCACHABLE)
+                       continue;
+               size = range_state[i].size_pfn;
+               if (!size)
+                       continue;
+               base = range_state[i].base_pfn;
+               subtract_range(range, base, base + size - 1);
+       }
+       if (extra_remove_size)
+               subtract_range(range, extra_remove_base,
+                                extra_remove_base + extra_remove_size  - 1);
+
+       /* get new range num */
+       nr_range = 0;
+       for (i = 0; i < RANGE_NUM; i++) {
+               if (!range[i].end)
+                       continue;
+               nr_range++;
+       }
+       if  (debug_print) {
+               printk(KERN_DEBUG "After UC checking\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* sort the ranges */
+       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+       if  (debug_print) {
+               printk(KERN_DEBUG "After sorting\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* clear those is not used */
+       for (i = nr_range; i < RANGE_NUM; i++)
+               memset(&range[i], 0, sizeof(range[i]));
+
+       return nr_range;
+}
+
+static struct res_range __initdata range[RANGE_NUM];
+
+#ifdef CONFIG_MTRR_SANITIZER
+
+static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
+{
+       unsigned long sum;
+       int i;
+
+       sum = 0;
+       for (i = 0; i < nr_range; i++)
+               sum += range[i].end + 1 - range[i].start;
+
+       return sum;
+}
+
+static int enable_mtrr_cleanup __initdata =
+       CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
+
+static int __init disable_mtrr_cleanup_setup(char *str)
+{
+       if (enable_mtrr_cleanup != -1)
+               enable_mtrr_cleanup = 0;
+       return 0;
+}
+early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
+
+static int __init enable_mtrr_cleanup_setup(char *str)
+{
+       if (enable_mtrr_cleanup != -1)
+               enable_mtrr_cleanup = 1;
+       return 0;
+}
+early_param("enble_mtrr_cleanup", enable_mtrr_cleanup_setup);
+
+struct var_mtrr_state {
+       unsigned long   range_startk;
+       unsigned long   range_sizek;
+       unsigned long   chunk_sizek;
+       unsigned long   gran_sizek;
+       unsigned int    reg;
+};
+
+static void __init
+set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
+               unsigned char type, unsigned int address_bits)
+{
+       u32 base_lo, base_hi, mask_lo, mask_hi;
+       u64 base, mask;
+
+       if (!sizek) {
+               fill_mtrr_var_range(reg, 0, 0, 0, 0);
+               return;
+       }
+
+       mask = (1ULL << address_bits) - 1;
+       mask &= ~((((u64)sizek) << 10) - 1);
+
+       base  = ((u64)basek) << 10;
+
+       base |= type;
+       mask |= 0x800;
+
+       base_lo = base & ((1ULL<<32) - 1);
+       base_hi = base >> 32;
+
+       mask_lo = mask & ((1ULL<<32) - 1);
+       mask_hi = mask >> 32;
+
+       fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
+}
+
+static void __init
+save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
+               unsigned char type)
+{
+       range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
+       range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
+       range_state[reg].type = type;
+}
+
+static void __init
+set_var_mtrr_all(unsigned int address_bits)
+{
+       unsigned long basek, sizek;
+       unsigned char type;
+       unsigned int reg;
+
+       for (reg = 0; reg < num_var_ranges; reg++) {
+               basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
+               sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
+               type = range_state[reg].type;
+
+               set_var_mtrr(reg, basek, sizek, type, address_bits);
+       }
+}
+
+static unsigned int __init
+range_to_mtrr(unsigned int reg, unsigned long range_startk,
+             unsigned long range_sizek, unsigned char type)
+{
+       if (!range_sizek || (reg >= num_var_ranges))
+               return reg;
+
+       while (range_sizek) {
+               unsigned long max_align, align;
+               unsigned long sizek;
+
+               /* Compute the maximum size I can make a range */
+               if (range_startk)
+                       max_align = ffs(range_startk) - 1;
+               else
+                       max_align = 32;
+               align = fls(range_sizek) - 1;
+               if (align > max_align)
+                       align = max_align;
+
+               sizek = 1 << align;
+               if (debug_print)
+                       printk(KERN_DEBUG "Setting variable MTRR %d, "
+                               "base: %ldMB, range: %ldMB, type %s\n",
+                               reg, range_startk >> 10, sizek >> 10,
+                               (type == MTRR_TYPE_UNCACHABLE)?"UC":
+                                   ((type == MTRR_TYPE_WRBACK)?"WB":"Other")
+                               );
+               save_var_mtrr(reg++, range_startk, sizek, type);
+               range_startk += sizek;
+               range_sizek -= sizek;
+               if (reg >= num_var_ranges)
+                       break;
+       }
+       return reg;
+}
+
+static unsigned __init
+range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
+                       unsigned long sizek)
+{
+       unsigned long hole_basek, hole_sizek;
+       unsigned long second_basek, second_sizek;
+       unsigned long range0_basek, range0_sizek;
+       unsigned long range_basek, range_sizek;
+       unsigned long chunk_sizek;
+       unsigned long gran_sizek;
+
+       hole_basek = 0;
+       hole_sizek = 0;
+       second_basek = 0;
+       second_sizek = 0;
+       chunk_sizek = state->chunk_sizek;
+       gran_sizek = state->gran_sizek;
+
+       /* align with gran size, prevent small block used up MTRRs */
+       range_basek = ALIGN(state->range_startk, gran_sizek);
+       if ((range_basek > basek) && basek)
+               return second_sizek;
+       state->range_sizek -= (range_basek - state->range_startk);
+       range_sizek = ALIGN(state->range_sizek, gran_sizek);
+
+       while (range_sizek > state->range_sizek) {
+               range_sizek -= gran_sizek;
+               if (!range_sizek)
+                       return 0;
+       }
+       state->range_sizek = range_sizek;
+
+       /* try to append some small hole */
+       range0_basek = state->range_startk;
+       range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
+       if (range0_sizek == state->range_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
+                               range0_basek<<10,
+                               (range0_basek + state->range_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range0_basek,
+                               state->range_sizek, MTRR_TYPE_WRBACK);
+               return 0;
+       }
+
+       range0_sizek -= chunk_sizek;
+       if (range0_sizek && sizek) {
+           while (range0_basek + range0_sizek > (basek + sizek)) {
+               range0_sizek -= chunk_sizek;
+               if (!range0_sizek)
+                       break;
+           }
+       }
+
+       if (range0_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "range0: %016lx - %016lx\n",
+                               range0_basek<<10,
+                               (range0_basek + range0_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range0_basek,
+                               range0_sizek, MTRR_TYPE_WRBACK);
+
+       }
+
+       range_basek = range0_basek + range0_sizek;
+       range_sizek = chunk_sizek;
+
+       if (range_basek + range_sizek > basek &&
+           range_basek + range_sizek <= (basek + sizek)) {
+               /* one hole */
+               second_basek = basek;
+               second_sizek = range_basek + range_sizek - basek;
+       }
+
+       /* if last piece, only could one hole near end */
+       if ((second_basek || !basek) &&
+           range_sizek - (state->range_sizek - range0_sizek) - second_sizek <
+           (chunk_sizek >> 1)) {
+               /*
+                * one hole in middle (second_sizek is 0) or at end
+                * (second_sizek is 0 )
+                */
+               hole_sizek = range_sizek - (state->range_sizek - range0_sizek)
+                                - second_sizek;
+               hole_basek = range_basek + range_sizek - hole_sizek
+                                - second_sizek;
+       } else {
+               /* fallback for big hole, or several holes */
+               range_sizek = state->range_sizek - range0_sizek;
+               second_basek = 0;
+               second_sizek = 0;
+       }
+
+       if (debug_print)
+               printk(KERN_DEBUG "range: %016lx - %016lx\n", range_basek<<10,
+                        (range_basek + range_sizek)<<10);
+       state->reg = range_to_mtrr(state->reg, range_basek, range_sizek,
+                                        MTRR_TYPE_WRBACK);
+       if (hole_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "hole: %016lx - %016lx\n",
+                                hole_basek<<10, (hole_basek + hole_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, hole_basek, hole_sizek,
+                                                MTRR_TYPE_UNCACHABLE);
+
+       }
+
+       return second_sizek;
+}
+
+static void __init
+set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
+                  unsigned long size_pfn)
+{
+       unsigned long basek, sizek;
+       unsigned long second_sizek = 0;
+
+       if (state->reg >= num_var_ranges)
+               return;
+
+       basek = base_pfn << (PAGE_SHIFT - 10);
+       sizek = size_pfn << (PAGE_SHIFT - 10);
+
+       /* See if I can merge with the last range */
+       if ((basek <= 1024) ||
+           (state->range_startk + state->range_sizek == basek)) {
+               unsigned long endk = basek + sizek;
+               state->range_sizek = endk - state->range_startk;
+               return;
+       }
+       /* Write the range mtrrs */
+       if (state->range_sizek != 0)
+               second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
+
+       /* Allocate an msr */
+       state->range_startk = basek + second_sizek;
+       state->range_sizek  = sizek - second_sizek;
+}
+
+/* mininum size of mtrr block that can take hole */
+static u64 mtrr_chunk_size __initdata = (256ULL<<20);
+
+static int __init parse_mtrr_chunk_size_opt(char *p)
+{
+       if (!p)
+               return -EINVAL;
+       mtrr_chunk_size = memparse(p, &p);
+       return 0;
+}
+early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
+
+/* granity of mtrr of block */
+static u64 mtrr_gran_size __initdata;
+
+static int __init parse_mtrr_gran_size_opt(char *p)
+{
+       if (!p)
+               return -EINVAL;
+       mtrr_gran_size = memparse(p, &p);
+       return 0;
+}
+early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
+
+static int nr_mtrr_spare_reg __initdata =
+                                CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
+
+static int __init parse_mtrr_spare_reg(char *arg)
+{
+       if (arg)
+               nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
+       return 0;
+}
+
+early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
+
+static int __init
+x86_setup_var_mtrrs(struct res_range *range, int nr_range,
+                   u64 chunk_size, u64 gran_size)
+{
+       struct var_mtrr_state var_state;
+       int i;
+       int num_reg;
+
+       var_state.range_startk  = 0;
+       var_state.range_sizek   = 0;
+       var_state.reg           = 0;
+       var_state.chunk_sizek   = chunk_size >> 10;
+       var_state.gran_sizek    = gran_size >> 10;
+
+       memset(range_state, 0, sizeof(range_state));
+
+       /* Write the range etc */
+       for (i = 0; i < nr_range; i++)
+               set_var_mtrr_range(&var_state, range[i].start,
+                                  range[i].end - range[i].start + 1);
+
+       /* Write the last range */
+       if (var_state.range_sizek != 0)
+               range_to_mtrr_with_hole(&var_state, 0, 0);
+
+       num_reg = var_state.reg;
+       /* Clear out the extra MTRR's */
+       while (var_state.reg < num_var_ranges) {
+               save_var_mtrr(var_state.reg, 0, 0, 0);
+               var_state.reg++;
+       }
+
+       return num_reg;
+}
+
+struct mtrr_cleanup_result {
+       unsigned long gran_sizek;
+       unsigned long chunk_sizek;
+       unsigned long lose_cover_sizek;
+       unsigned int num_reg;
+       int bad;
+};
+
+/*
+ * gran_size: 1M, 2M, ..., 2G
+ * chunk size: gran_size, ..., 4G
+ * so we need (2+13)*6
+ */
+#define NUM_RESULT     90
+#define PSHIFT         (PAGE_SHIFT - 10)
+
+static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
+static struct res_range __initdata range_new[RANGE_NUM];
+static unsigned long __initdata min_loss_pfn[RANGE_NUM];
+
+static int __init mtrr_cleanup(unsigned address_bits)
+{
+       unsigned long extra_remove_base, extra_remove_size;
+       unsigned long i, base, size, def, dummy;
+       mtrr_type type;
+       int nr_range, nr_range_new;
+       u64 chunk_size, gran_size;
+       unsigned long range_sums, range_sums_new;
+       int index_good;
+       int num_reg_good;
+
+       /* extra one for all 0 */
+       int num[MTRR_NUM_TYPES + 1];
+
+       if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
+               return 0;
+       rdmsr(MTRRdefType_MSR, def, dummy);
+       def &= 0xff;
+       if (def != MTRR_TYPE_UNCACHABLE)
+               return 0;
+
+       /* get it and store it aside */
+       memset(range_state, 0, sizeof(range_state));
+       for (i = 0; i < num_var_ranges; i++) {
+               mtrr_if->get(i, &base, &size, &type);
+               range_state[i].base_pfn = base;
+               range_state[i].size_pfn = size;
+               range_state[i].type = type;
+       }
+
+       /* check entries number */
+       memset(num, 0, sizeof(num));
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               size = range_state[i].size_pfn;
+               if (type >= MTRR_NUM_TYPES)
+                       continue;
+               if (!size)
+                       type = MTRR_NUM_TYPES;
+               num[type]++;
+       }
+
+       /* check if we got UC entries */
+       if (!num[MTRR_TYPE_UNCACHABLE])
+               return 0;
+
+       /* check if we only had WB and UC */
+       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
+               num_var_ranges - num[MTRR_NUM_TYPES])
+               return 0;
+
+       memset(range, 0, sizeof(range));
+       extra_remove_size = 0;
+       if (mtrr_tom2) {
+               extra_remove_base = 1 << (32 - PAGE_SHIFT);
+               extra_remove_size =
+                       (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
+       }
+       nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
+                                         extra_remove_size);
+       range_sums = sum_ranges(range, nr_range);
+       printk(KERN_INFO "total RAM coverred: %ldM\n",
+              range_sums >> (20 - PAGE_SHIFT));
+
+       if (mtrr_chunk_size && mtrr_gran_size) {
+               int num_reg;
+
+               debug_print = 1;
+               /* convert ranges to var ranges state */
+               num_reg = x86_setup_var_mtrrs(range, nr_range, mtrr_chunk_size,
+                                             mtrr_gran_size);
+
+               /* we got new setting in range_state, check it */
+               memset(range_new, 0, sizeof(range_new));
+               nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
+                                                     extra_remove_base,
+                                                     extra_remove_size);
+               range_sums_new = sum_ranges(range_new, nr_range_new);
+
+               i = 0;
+               result[i].chunk_sizek = mtrr_chunk_size >> 10;
+               result[i].gran_sizek = mtrr_gran_size >> 10;
+               result[i].num_reg = num_reg;
+               if (range_sums < range_sums_new) {
+                       result[i].lose_cover_sizek =
+                               (range_sums_new - range_sums) << PSHIFT;
+                       result[i].bad = 1;
+               } else
+                       result[i].lose_cover_sizek =
+                               (range_sums - range_sums_new) << PSHIFT;
+
+               printk(KERN_INFO "%sgran_size: %ldM \tchunk_size: %ldM \t",
+                        result[i].bad?"*BAD*":" ", result[i].gran_sizek >> 10,
+                        result[i].chunk_sizek >> 10);
+               printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ldM \n",
+                        result[i].num_reg, result[i].bad?"-":"",
+                        result[i].lose_cover_sizek >> 10);
+               if (!result[i].bad) {
+                       set_var_mtrr_all(address_bits);
+                       return 1;
+               }
+               printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
+                      "will find optimal one\n");
+               debug_print = 0;
+               memset(result, 0, sizeof(result[0]));
+       }
+
+       i = 0;
+       memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
+       memset(result, 0, sizeof(result));
+       for (gran_size = (1ULL<<20); gran_size < (1ULL<<32); gran_size <<= 1) {
+               for (chunk_size = gran_size; chunk_size < (1ULL<<33);
+                    chunk_size <<= 1) {
+                       int num_reg;
+
+                       if (debug_print)
+                               printk(KERN_INFO
+                              "\ngran_size: %lldM   chunk_size_size: %lldM\n",
+                                      gran_size >> 20, chunk_size >> 20);
+                       if (i >= NUM_RESULT)
+                               continue;
+
+                       /* convert ranges to var ranges state */
+                       num_reg = x86_setup_var_mtrrs(range, nr_range,
+                                                        chunk_size, gran_size);
+
+                       /* we got new setting in range_state, check it */
+                       memset(range_new, 0, sizeof(range_new));
+                       nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
+                                        extra_remove_base, extra_remove_size);
+                       range_sums_new = sum_ranges(range_new, nr_range_new);
+
+                       result[i].chunk_sizek = chunk_size >> 10;
+                       result[i].gran_sizek = gran_size >> 10;
+                       result[i].num_reg = num_reg;
+                       if (range_sums < range_sums_new) {
+                               result[i].lose_cover_sizek =
+                                       (range_sums_new - range_sums) << PSHIFT;
+                               result[i].bad = 1;
+                       } else
+                               result[i].lose_cover_sizek =
+                                       (range_sums - range_sums_new) << PSHIFT;
+
+                       /* double check it */
+                       if (!result[i].bad && !result[i].lose_cover_sizek) {
+                               if (nr_range_new != nr_range ||
+                                       memcmp(range, range_new, sizeof(range)))
+                                               result[i].bad = 1;
+                       }
+
+                       if (!result[i].bad && (range_sums - range_sums_new <
+                                              min_loss_pfn[num_reg])) {
+                               min_loss_pfn[num_reg] =
+                                       range_sums - range_sums_new;
+                       }
+                       i++;
+               }
+       }
+
+       /* print out all */
+       for (i = 0; i < NUM_RESULT; i++) {
+               printk(KERN_INFO "%sgran_size: %ldM \tchunk_size: %ldM \t",
+                      result[i].bad?"*BAD* ":" ", result[i].gran_sizek >> 10,
+                      result[i].chunk_sizek >> 10);
+               printk(KERN_CONT "num_reg: %d \tlose RAM: %s%ldM\n",
+                      result[i].num_reg, result[i].bad?"-":"",
+                      result[i].lose_cover_sizek >> 10);
+       }
+
+       /* try to find the optimal index */
+       if (nr_mtrr_spare_reg >= num_var_ranges)
+               nr_mtrr_spare_reg = num_var_ranges - 1;
+       num_reg_good = -1;
+       for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
+               if (!min_loss_pfn[i]) {
+                       num_reg_good = i;
+                       break;
+               }
+       }
+
+       index_good = -1;
+       if (num_reg_good != -1) {
+               for (i = 0; i < NUM_RESULT; i++) {
+                       if (!result[i].bad &&
+                           result[i].num_reg == num_reg_good &&
+                           !result[i].lose_cover_sizek) {
+                               index_good = i;
+                               break;
+                       }
+               }
+       }
+
+       if (index_good != -1) {
+               printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
+               i = index_good;
+               printk(KERN_INFO "gran_size: %ldM \tchunk_size: %ldM \t",
+                               result[i].gran_sizek >> 10,
+                               result[i].chunk_sizek >> 10);
+               printk(KERN_CONT "num_reg: %d \tlose RAM: %ldM\n",
+                               result[i].num_reg,
+                               result[i].lose_cover_sizek >> 10);
+               /* convert ranges to var ranges state */
+               chunk_size = result[i].chunk_sizek;
+               chunk_size <<= 10;
+               gran_size = result[i].gran_sizek;
+               gran_size <<= 10;
+               debug_print = 1;
+               x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
+               set_var_mtrr_all(address_bits);
+               return 1;
+       }
+
+       printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
+       printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
+
+       return 0;
+}
+#else
+static int __init mtrr_cleanup(unsigned address_bits)
+{
+       return 0;
+}
+#endif
+
+static int __initdata changed_by_mtrr_cleanup;
+
 static int disable_mtrr_trim;
 
 static int __init disable_mtrr_trim_setup(char *str)
@@ -648,6 +1430,19 @@ int __init amd_special_default_mtrr(void)
        return 0;
 }
 
+static u64 __init real_trim_memory(unsigned long start_pfn,
+                                  unsigned long limit_pfn)
+{
+       u64 trim_start, trim_size;
+       trim_start = start_pfn;
+       trim_start <<= PAGE_SHIFT;
+       trim_size = limit_pfn;
+       trim_size <<= PAGE_SHIFT;
+       trim_size -= trim_start;
+
+       return e820_update_range(trim_start, trim_size, E820_RAM,
+                               E820_RESERVED);
+}
 /**
  * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
  * @end_pfn: ending page frame number
@@ -663,8 +1458,11 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
 {
        unsigned long i, base, size, highest_pfn = 0, def, dummy;
        mtrr_type type;
-       u64 trim_start, trim_size;
+       int nr_range;
+       u64 total_trim_size;
 
+       /* extra one for all 0 */
+       int num[MTRR_NUM_TYPES + 1];
        /*
         * Make sure we only trim uncachable memory on machines that
         * support the Intel MTRR architecture:
@@ -676,14 +1474,22 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
        if (def != MTRR_TYPE_UNCACHABLE)
                return 0;
 
-       if (amd_special_default_mtrr())
-               return 0;
+       /* get it and store it aside */
+       memset(range_state, 0, sizeof(range_state));
+       for (i = 0; i < num_var_ranges; i++) {
+               mtrr_if->get(i, &base, &size, &type);
+               range_state[i].base_pfn = base;
+               range_state[i].size_pfn = size;
+               range_state[i].type = type;
+       }
 
        /* Find highest cached pfn */
        for (i = 0; i < num_var_ranges; i++) {
-               mtrr_if->get(i, &base, &size, &type);
+               type = range_state[i].type;
                if (type != MTRR_TYPE_WRBACK)
                        continue;
+               base = range_state[i].base_pfn;
+               size = range_state[i].size_pfn;
                if (highest_pfn < base + size)
                        highest_pfn = base + size;
        }
@@ -698,22 +1504,65 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
                return 0;
        }
 
-       if (highest_pfn < end_pfn) {
+       /* check entries number */
+       memset(num, 0, sizeof(num));
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type >= MTRR_NUM_TYPES)
+                       continue;
+               size = range_state[i].size_pfn;
+               if (!size)
+                       type = MTRR_NUM_TYPES;
+               num[type]++;
+       }
+
+       /* no entry for WB? */
+       if (!num[MTRR_TYPE_WRBACK])
+               return 0;
+
+       /* check if we only had WB and UC */
+       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
+               num_var_ranges - num[MTRR_NUM_TYPES])
+               return 0;
+
+       memset(range, 0, sizeof(range));
+       nr_range = 0;
+       if (mtrr_tom2) {
+               range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
+               range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
+               if (highest_pfn < range[nr_range].end + 1)
+                       highest_pfn = range[nr_range].end + 1;
+               nr_range++;
+       }
+       nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
+
+       total_trim_size = 0;
+       /* check the head */
+       if (range[0].start)
+               total_trim_size += real_trim_memory(0, range[0].start);
+       /* check the holes */
+       for (i = 0; i < nr_range - 1; i++) {
+               if (range[i].end + 1 < range[i+1].start)
+                       total_trim_size += real_trim_memory(range[i].end + 1,
+                                                           range[i+1].start);
+       }
+       /* check the top */
+       i = nr_range - 1;
+       if (range[i].end + 1 < end_pfn)
+               total_trim_size += real_trim_memory(range[i].end + 1,
+                                                        end_pfn);
+
+       if (total_trim_size) {
                printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
-                       " all of memory, losing %luMB of RAM.\n",
-                       (end_pfn - highest_pfn) >> (20 - PAGE_SHIFT));
+                       " all of memory, losing %lluMB of RAM.\n",
+                       total_trim_size >> 20);
 
-               WARN_ON(1);
+               if (!changed_by_mtrr_cleanup)
+                       WARN_ON(1);
 
                printk(KERN_INFO "update e820 for mtrr\n");
-               trim_start = highest_pfn;
-               trim_start <<= PAGE_SHIFT;
-               trim_size = end_pfn;
-               trim_size <<= PAGE_SHIFT;
-               trim_size -= trim_start;
-               update_memory_range(trim_start, trim_size, E820_RAM,
-                                       E820_RESERVED);
                update_e820();
+
                return 1;
        }
 
@@ -729,18 +1578,21 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
  */
 void __init mtrr_bp_init(void)
 {
+       u32 phys_addr;
        init_ifs();
 
+       phys_addr = 32;
+
        if (cpu_has_mtrr) {
                mtrr_if = &generic_mtrr_ops;
                size_or_mask = 0xff000000;      /* 36 bits */
                size_and_mask = 0x00f00000;
+               phys_addr = 36;
 
                /* This is an AMD specific MSR, but we assume(hope?) that
                   Intel will implement it to when they extend the address
                   bus of the Xeon. */
                if (cpuid_eax(0x80000000) >= 0x80000008) {
-                       u32 phys_addr;
                        phys_addr = cpuid_eax(0x80000008) & 0xff;
                        /* CPUID workaround for Intel 0F33/0F34 CPU */
                        if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
@@ -758,6 +1610,7 @@ void __init mtrr_bp_init(void)
                           don't support PAE */
                        size_or_mask = 0xfff00000;      /* 32 bits */
                        size_and_mask = 0;
+                       phys_addr = 32;
                }
        } else {
                switch (boot_cpu_data.x86_vendor) {
@@ -791,8 +1644,15 @@ void __init mtrr_bp_init(void)
        if (mtrr_if) {
                set_num_var_ranges();
                init_table();
-               if (use_intel())
+               if (use_intel()) {
                        get_mtrr_state();
+
+                       if (mtrr_cleanup(phys_addr)) {
+                               changed_by_mtrr_cleanup = 1;
+                               mtrr_if->set_all();
+                       }
+
+               }
        }
 }
 
@@ -829,9 +1689,10 @@ static int __init mtrr_init_finialize(void)
 {
        if (!mtrr_if)
                return 0;
-       if (use_intel())
-               mtrr_state_warn();
-       else {
+       if (use_intel()) {
+               if (!changed_by_mtrr_cleanup)
+                       mtrr_state_warn();
+       } else {
                /* The CPUs haven't MTRR and seem to not support SMP. They have
                 * specific drivers, we use a tricky method to support
                 * suspend/resume for them.
index 2cc77eb6fea36967f7defdbae74359ebaac14ebb..2dc4ec656b23c22c9d3806cd57746d4c834b5166 100644 (file)
@@ -81,6 +81,8 @@ void set_mtrr_done(struct set_mtrr_context *ctxt);
 void set_mtrr_cache_disable(struct set_mtrr_context *ctxt);
 void set_mtrr_prepare_save(struct set_mtrr_context *ctxt);
 
+void fill_mtrr_var_range(unsigned int index,
+               u32 base_lo, u32 base_hi, u32 mask_lo, u32 mask_hi);
 void get_mtrr_state(void);
 
 extern void set_mtrr_ops(struct mtrr_ops * ops);
@@ -92,6 +94,7 @@ extern struct mtrr_ops * mtrr_if;
 #define use_intel()    (mtrr_if && mtrr_if->use_intel_if == 1)
 
 extern unsigned int num_var_ranges;
+extern u64 mtrr_tom2;
 
 void mtrr_state_warn(void);
 const char *mtrr_attrib_to_str(int x);
index f9ae93adffe5a58619b2c687e39cfbb43e00d987..2e9bef6e3aa3d8ee0f778164725f024b6b7c388f 100644 (file)
@@ -1,11 +1,15 @@
-/* local apic based NMI watchdog for various CPUs.
-   This file also handles reservation of performance counters for coordination
-   with other users (like oprofile).
-
-   Note that these events normally don't tick when the CPU idles. This means
-   the frequency varies with CPU load.
-
-   Original code for K7/P6 written by Keith Owens */
+/*
+ * local apic based NMI watchdog for various CPUs.
+ *
+ * This file also handles reservation of performance counters for coordination
+ * with other users (like oprofile).
+ *
+ * Note that these events normally don't tick when the CPU idles. This means
+ * the frequency varies with CPU load.
+ *
+ * Original code for K7/P6 written by Keith Owens
+ *
+ */
 
 #include <linux/percpu.h>
 #include <linux/module.h>
@@ -36,12 +40,16 @@ struct wd_ops {
 
 static const struct wd_ops *wd_ops;
 
-/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
- * offset from MSR_P4_BSU_ESCR0.  It will be the max for all platforms (for now)
+/*
+ * this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
+ * offset from MSR_P4_BSU_ESCR0.
+ *
+ * It will be the max for all platforms (for now)
  */
 #define NMI_MAX_COUNTER_BITS 66
 
-/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
+/*
+ * perfctr_nmi_owner tracks the ownership of the perfctr registers:
  * evtsel_nmi_owner tracks the ownership of the event selection
  * - different performance counters/ event selection may be reserved for
  *   different subsystems this reservation system just tries to coordinate
@@ -73,8 +81,10 @@ static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
        return 0;
 }
 
-/* converts an msr to an appropriate reservation bit */
-/* returns the bit offset of the event selection register */
+/*
+ * converts an msr to an appropriate reservation bit
+ * returns the bit offset of the event selection register
+ */
 static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
 {
        /* returns the bit offset of the event selection register */
@@ -114,6 +124,7 @@ int avail_to_resrv_perfctr_nmi(unsigned int msr)
 
        return (!test_bit(counter, perfctr_nmi_owner));
 }
+EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
 
 int reserve_perfctr_nmi(unsigned int msr)
 {
@@ -128,6 +139,7 @@ int reserve_perfctr_nmi(unsigned int msr)
                return 1;
        return 0;
 }
+EXPORT_SYMBOL(reserve_perfctr_nmi);
 
 void release_perfctr_nmi(unsigned int msr)
 {
@@ -140,6 +152,7 @@ void release_perfctr_nmi(unsigned int msr)
 
        clear_bit(counter, perfctr_nmi_owner);
 }
+EXPORT_SYMBOL(release_perfctr_nmi);
 
 int reserve_evntsel_nmi(unsigned int msr)
 {
@@ -154,6 +167,7 @@ int reserve_evntsel_nmi(unsigned int msr)
                return 1;
        return 0;
 }
+EXPORT_SYMBOL(reserve_evntsel_nmi);
 
 void release_evntsel_nmi(unsigned int msr)
 {
@@ -166,11 +180,6 @@ void release_evntsel_nmi(unsigned int msr)
 
        clear_bit(counter, evntsel_nmi_owner);
 }
-
-EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
-EXPORT_SYMBOL(reserve_perfctr_nmi);
-EXPORT_SYMBOL(release_perfctr_nmi);
-EXPORT_SYMBOL(reserve_evntsel_nmi);
 EXPORT_SYMBOL(release_evntsel_nmi);
 
 void disable_lapic_nmi_watchdog(void)
@@ -181,7 +190,9 @@ void disable_lapic_nmi_watchdog(void)
                return;
 
        on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-       wd_ops->unreserve();
+
+       if (wd_ops)
+               wd_ops->unreserve();
 
        BUG_ON(atomic_read(&nmi_active) != 0);
 }
@@ -232,8 +243,8 @@ static unsigned int adjust_for_32bit_ctr(unsigned int hz)
        return retval;
 }
 
-static void
-write_watchdog_counter(unsigned int perfctr_msr, const char *descr, unsigned nmi_hz)
+static void write_watchdog_counter(unsigned int perfctr_msr,
+                               const char *descr, unsigned nmi_hz)
 {
        u64 count = (u64)cpu_khz * 1000;
 
@@ -244,7 +255,7 @@ write_watchdog_counter(unsigned int perfctr_msr, const char *descr, unsigned nmi
 }
 
 static void write_watchdog_counter32(unsigned int perfctr_msr,
-               const char *descr, unsigned nmi_hz)
+                               const char *descr, unsigned nmi_hz)
 {
        u64 count = (u64)cpu_khz * 1000;
 
@@ -254,9 +265,10 @@ static void write_watchdog_counter32(unsigned int perfctr_msr,
        wrmsr(perfctr_msr, (u32)(-count), 0);
 }
 
-/* AMD K7/K8/Family10h/Family11h support. AMD keeps this interface
-   nicely stable so there is not much variety */
-
+/*
+ * AMD K7/K8/Family10h/Family11h support.
+ * AMD keeps this interface nicely stable so there is not much variety
+ */
 #define K7_EVNTSEL_ENABLE      (1 << 22)
 #define K7_EVNTSEL_INT         (1 << 20)
 #define K7_EVNTSEL_OS          (1 << 17)
@@ -289,7 +301,7 @@ static int setup_k7_watchdog(unsigned nmi_hz)
 
        wd->perfctr_msr = perfctr_msr;
        wd->evntsel_msr = evntsel_msr;
-       wd->cccr_msr = 0;  //unused
+       wd->cccr_msr = 0;  /* unused */
        return 1;
 }
 
@@ -325,18 +337,19 @@ static void single_msr_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
 }
 
 static const struct wd_ops k7_wd_ops = {
-       .reserve = single_msr_reserve,
-       .unreserve = single_msr_unreserve,
-       .setup = setup_k7_watchdog,
-       .rearm = single_msr_rearm,
-       .stop = single_msr_stop_watchdog,
-       .perfctr = MSR_K7_PERFCTR0,
-       .evntsel = MSR_K7_EVNTSEL0,
-       .checkbit = 1ULL<<47,
+       .reserve        = single_msr_reserve,
+       .unreserve      = single_msr_unreserve,
+       .setup          = setup_k7_watchdog,
+       .rearm          = single_msr_rearm,
+       .stop           = single_msr_stop_watchdog,
+       .perfctr        = MSR_K7_PERFCTR0,
+       .evntsel        = MSR_K7_EVNTSEL0,
+       .checkbit       = 1ULL << 47,
 };
 
-/* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
-
+/*
+ * Intel Model 6 (PPro+,P2,P3,P-M,Core1)
+ */
 #define P6_EVNTSEL0_ENABLE     (1 << 22)
 #define P6_EVNTSEL_INT         (1 << 20)
 #define P6_EVNTSEL_OS          (1 << 17)
@@ -372,52 +385,58 @@ static int setup_p6_watchdog(unsigned nmi_hz)
 
        wd->perfctr_msr = perfctr_msr;
        wd->evntsel_msr = evntsel_msr;
-       wd->cccr_msr = 0;  //unused
+       wd->cccr_msr = 0;  /* unused */
        return 1;
 }
 
 static void p6_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
 {
-       /* P6 based Pentium M need to re-unmask
+       /*
+        * P6 based Pentium M need to re-unmask
         * the apic vector but it doesn't hurt
         * other P6 variant.
-        * ArchPerfom/Core Duo also needs this */
+        * ArchPerfom/Core Duo also needs this
+        */
        apic_write(APIC_LVTPC, APIC_DM_NMI);
+
        /* P6/ARCH_PERFMON has 32 bit counter write */
        write_watchdog_counter32(wd->perfctr_msr, NULL,nmi_hz);
 }
 
 static const struct wd_ops p6_wd_ops = {
-       .reserve = single_msr_reserve,
-       .unreserve = single_msr_unreserve,
-       .setup = setup_p6_watchdog,
-       .rearm = p6_rearm,
-       .stop = single_msr_stop_watchdog,
-       .perfctr = MSR_P6_PERFCTR0,
-       .evntsel = MSR_P6_EVNTSEL0,
-       .checkbit = 1ULL<<39,
+       .reserve        = single_msr_reserve,
+       .unreserve      = single_msr_unreserve,
+       .setup          = setup_p6_watchdog,
+       .rearm          = p6_rearm,
+       .stop           = single_msr_stop_watchdog,
+       .perfctr        = MSR_P6_PERFCTR0,
+       .evntsel        = MSR_P6_EVNTSEL0,
+       .checkbit       = 1ULL << 39,
 };
 
-/* Intel P4 performance counters. By far the most complicated of all. */
-
-#define MSR_P4_MISC_ENABLE_PERF_AVAIL  (1<<7)
-#define P4_ESCR_EVENT_SELECT(N)        ((N)<<25)
-#define P4_ESCR_OS             (1<<3)
-#define P4_ESCR_USR            (1<<2)
-#define P4_CCCR_OVF_PMI0       (1<<26)
-#define P4_CCCR_OVF_PMI1       (1<<27)
-#define P4_CCCR_THRESHOLD(N)   ((N)<<20)
-#define P4_CCCR_COMPLEMENT     (1<<19)
-#define P4_CCCR_COMPARE                (1<<18)
-#define P4_CCCR_REQUIRED       (3<<16)
-#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
-#define P4_CCCR_ENABLE         (1<<12)
-#define P4_CCCR_OVF            (1<<31)
-
-/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
-   CRU_ESCR0 (with any non-null event selector) through a complemented
-   max threshold. [IA32-Vol3, Section 14.9.9] */
+/*
+ * Intel P4 performance counters.
+ * By far the most complicated of all.
+ */
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL  (1 << 7)
+#define P4_ESCR_EVENT_SELECT(N)        ((N) << 25)
+#define P4_ESCR_OS             (1 << 3)
+#define P4_ESCR_USR            (1 << 2)
+#define P4_CCCR_OVF_PMI0       (1 << 26)
+#define P4_CCCR_OVF_PMI1       (1 << 27)
+#define P4_CCCR_THRESHOLD(N)   ((N) << 20)
+#define P4_CCCR_COMPLEMENT     (1 << 19)
+#define P4_CCCR_COMPARE                (1 << 18)
+#define P4_CCCR_REQUIRED       (3 << 16)
+#define P4_CCCR_ESCR_SELECT(N) ((N) << 13)
+#define P4_CCCR_ENABLE         (1 << 12)
+#define P4_CCCR_OVF            (1 << 31)
 
+/*
+ * Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+ * CRU_ESCR0 (with any non-null event selector) through a complemented
+ * max threshold. [IA32-Vol3, Section 14.9.9]
+ */
 static int setup_p4_watchdog(unsigned nmi_hz)
 {
        unsigned int perfctr_msr, evntsel_msr, cccr_msr;
@@ -442,7 +461,8 @@ static int setup_p4_watchdog(unsigned nmi_hz)
 #endif
                ht_num = 0;
 
-       /* performance counters are shared resources
+       /*
+        * performance counters are shared resources
         * assign each hyperthread its own set
         * (re-use the ESCR0 register, seems safe
         * and keeps the cccr_val the same)
@@ -540,20 +560,21 @@ static void p4_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
 }
 
 static const struct wd_ops p4_wd_ops = {
-       .reserve = p4_reserve,
-       .unreserve = p4_unreserve,
-       .setup = setup_p4_watchdog,
-       .rearm = p4_rearm,
-       .stop = stop_p4_watchdog,
+       .reserve        = p4_reserve,
+       .unreserve      = p4_unreserve,
+       .setup          = setup_p4_watchdog,
+       .rearm          = p4_rearm,
+       .stop           = stop_p4_watchdog,
        /* RED-PEN this is wrong for the other sibling */
-       .perfctr = MSR_P4_BPU_PERFCTR0,
-       .evntsel = MSR_P4_BSU_ESCR0,
-       .checkbit = 1ULL<<39,
+       .perfctr        = MSR_P4_BPU_PERFCTR0,
+       .evntsel        = MSR_P4_BSU_ESCR0,
+       .checkbit       = 1ULL << 39,
 };
 
-/* Watchdog using the Intel architected PerfMon. Used for Core2 and hopefully
-   all future Intel CPUs. */
-
+/*
+ * Watchdog using the Intel architected PerfMon.
+ * Used for Core2 and hopefully all future Intel CPUs.
+ */
 #define ARCH_PERFMON_NMI_EVENT_SEL     ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
 #define ARCH_PERFMON_NMI_EVENT_UMASK   ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
 
@@ -599,19 +620,19 @@ static int setup_intel_arch_watchdog(unsigned nmi_hz)
 
        wd->perfctr_msr = perfctr_msr;
        wd->evntsel_msr = evntsel_msr;
-       wd->cccr_msr = 0;  //unused
+       wd->cccr_msr = 0;  /* unused */
        intel_arch_wd_ops.checkbit = 1ULL << (eax.split.bit_width - 1);
        return 1;
 }
 
 static struct wd_ops intel_arch_wd_ops __read_mostly = {
-       .reserve = single_msr_reserve,
-       .unreserve = single_msr_unreserve,
-       .setup = setup_intel_arch_watchdog,
-       .rearm = p6_rearm,
-       .stop = single_msr_stop_watchdog,
-       .perfctr = MSR_ARCH_PERFMON_PERFCTR1,
-       .evntsel = MSR_ARCH_PERFMON_EVENTSEL1,
+       .reserve        = single_msr_reserve,
+       .unreserve      = single_msr_unreserve,
+       .setup          = setup_intel_arch_watchdog,
+       .rearm          = p6_rearm,
+       .stop           = single_msr_stop_watchdog,
+       .perfctr        = MSR_ARCH_PERFMON_PERFCTR1,
+       .evntsel        = MSR_ARCH_PERFMON_EVENTSEL1,
 };
 
 static void probe_nmi_watchdog(void)
@@ -624,8 +645,10 @@ static void probe_nmi_watchdog(void)
                wd_ops = &k7_wd_ops;
                break;
        case X86_VENDOR_INTEL:
-               /* Work around Core Duo (Yonah) errata AE49 where perfctr1
-                  doesn't have a working enable bit. */
+               /*
+                * Work around Core Duo (Yonah) errata AE49 where perfctr1
+                * doesn't have a working enable bit.
+                */
                if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 14) {
                        intel_arch_wd_ops.perfctr = MSR_ARCH_PERFMON_PERFCTR0;
                        intel_arch_wd_ops.evntsel = MSR_ARCH_PERFMON_EVENTSEL0;
@@ -636,7 +659,7 @@ static void probe_nmi_watchdog(void)
                }
                switch (boot_cpu_data.x86) {
                case 6:
-                       if (boot_cpu_data.x86_model > 0xd)
+                       if (boot_cpu_data.x86_model > 13)
                                return;
 
                        wd_ops = &p6_wd_ops;
@@ -697,10 +720,11 @@ int lapic_wd_event(unsigned nmi_hz)
 {
        struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
        u64 ctr;
+
        rdmsrl(wd->perfctr_msr, ctr);
-       if (ctr & wd_ops->checkbit) /* perfctr still running? */
+       if (ctr & wd_ops->checkbit) /* perfctr still running? */
                return 0;
-       }
+
        wd_ops->rearm(wd, nmi_hz);
        return 1;
 }
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
new file mode 100644 (file)
index 0000000..28c2918
--- /dev/null
@@ -0,0 +1,1390 @@
+/*
+ * Handle the memory map.
+ * The functions here do the job until bootmem takes over.
+ *
+ *  Getting sanitize_e820_map() in sync with i386 version by applying change:
+ *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *     Alex Achenbach <xela@slit.de>, December 2002.
+ *  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/kexec.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/pfn.h>
+#include <linux/suspend.h>
+#include <linux/firmware-map.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/e820.h>
+#include <asm/proto.h>
+#include <asm/setup.h>
+#include <asm/trampoline.h>
+
+/*
+ * The e820 map is the map that gets modified e.g. with command line parameters
+ * and that is also registered with modifications in the kernel resource tree
+ * with the iomem_resource as parent.
+ *
+ * The e820_saved is directly saved after the BIOS-provided memory map is
+ * copied. It doesn't get modified afterwards. It's registered for the
+ * /sys/firmware/memmap interface.
+ *
+ * That memory map is not modified and is used as base for kexec. The kexec'd
+ * kernel should get the same memory map as the firmware provides. Then the
+ * user can e.g. boot the original kernel with mem=1G while still booting the
+ * next kernel with full memory.
+ */
+struct e820map e820;
+struct e820map e820_saved;
+
+/* For PCI or other memory-mapped resources */
+unsigned long pci_mem_start = 0xaeedbabe;
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_mem_start);
+#endif
+
+/*
+ * This function checks if any part of the range <start,end> is mapped
+ * with type.
+ */
+int
+e820_any_mapped(u64 start, u64 end, unsigned type)
+{
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+
+               if (type && ei->type != type)
+                       continue;
+               if (ei->addr >= end || ei->addr + ei->size <= start)
+                       continue;
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(e820_any_mapped);
+
+/*
+ * This function checks if the entire range <start,end> is mapped with type.
+ *
+ * Note: this function only works correct if the e820 table is sorted and
+ * not-overlapping, which is the case
+ */
+int __init e820_all_mapped(u64 start, u64 end, unsigned type)
+{
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+
+               if (type && ei->type != type)
+                       continue;
+               /* is the region (part) in overlap with the current region ?*/
+               if (ei->addr >= end || ei->addr + ei->size <= start)
+                       continue;
+
+               /* if the region is at the beginning of <start,end> we move
+                * start to the end of the region since it's ok until there
+                */
+               if (ei->addr <= start)
+                       start = ei->addr + ei->size;
+               /*
+                * if start is now at or beyond end, we're done, full
+                * coverage
+                */
+               if (start >= end)
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Add a memory region to the kernel e820 map.
+ */
+void __init e820_add_region(u64 start, u64 size, int type)
+{
+       int x = e820.nr_map;
+
+       if (x == ARRAY_SIZE(e820.map)) {
+               printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
+               return;
+       }
+
+       e820.map[x].addr = start;
+       e820.map[x].size = size;
+       e820.map[x].type = type;
+       e820.nr_map++;
+}
+
+void __init e820_print_map(char *who)
+{
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               printk(KERN_INFO " %s: %016Lx - %016Lx ", who,
+                      (unsigned long long) e820.map[i].addr,
+                      (unsigned long long)
+                      (e820.map[i].addr + e820.map[i].size));
+               switch (e820.map[i].type) {
+               case E820_RAM:
+               case E820_RESERVED_KERN:
+                       printk(KERN_CONT "(usable)\n");
+                       break;
+               case E820_RESERVED:
+                       printk(KERN_CONT "(reserved)\n");
+                       break;
+               case E820_ACPI:
+                       printk(KERN_CONT "(ACPI data)\n");
+                       break;
+               case E820_NVS:
+                       printk(KERN_CONT "(ACPI NVS)\n");
+                       break;
+               default:
+                       printk(KERN_CONT "type %u\n", e820.map[i].type);
+                       break;
+               }
+       }
+}
+
+/*
+ * Sanitize the BIOS e820 map.
+ *
+ * Some e820 responses include overlapping entries. The following
+ * replaces the original e820 map with a new one, removing overlaps,
+ * and resolving conflicting memory types in favor of highest
+ * numbered type.
+ *
+ * The input parameter biosmap points to an array of 'struct
+ * e820entry' which on entry has elements in the range [0, *pnr_map)
+ * valid, and which has space for up to max_nr_map entries.
+ * On return, the resulting sanitized e820 map entries will be in
+ * overwritten in the same location, starting at biosmap.
+ *
+ * The integer pointed to by pnr_map must be valid on entry (the
+ * current number of valid entries located at biosmap) and will
+ * be updated on return, with the new number of valid entries
+ * (something no more than max_nr_map.)
+ *
+ * The return value from sanitize_e820_map() is zero if it
+ * successfully 'sanitized' the map entries passed in, and is -1
+ * if it did nothing, which can happen if either of (1) it was
+ * only passed one map entry, or (2) any of the input map entries
+ * were invalid (start + size < start, meaning that the size was
+ * so big the described memory range wrapped around through zero.)
+ *
+ *     Visually we're performing the following
+ *     (1,2,3,4 = memory types)...
+ *
+ *     Sample memory map (w/overlaps):
+ *        ____22__________________
+ *        ______________________4_
+ *        ____1111________________
+ *        _44_____________________
+ *        11111111________________
+ *        ____________________33__
+ *        ___________44___________
+ *        __________33333_________
+ *        ______________22________
+ *        ___________________2222_
+ *        _________111111111______
+ *        _____________________11_
+ *        _________________4______
+ *
+ *     Sanitized equivalent (no overlap):
+ *        1_______________________
+ *        _44_____________________
+ *        ___1____________________
+ *        ____22__________________
+ *        ______11________________
+ *        _________1______________
+ *        __________3_____________
+ *        ___________44___________
+ *        _____________33_________
+ *        _______________2________
+ *        ________________1_______
+ *        _________________4______
+ *        ___________________2____
+ *        ____________________33__
+ *        ______________________4_
+ */
+
+int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
+                               int *pnr_map)
+{
+       struct change_member {
+               struct e820entry *pbios; /* pointer to original bios entry */
+               unsigned long long addr; /* address for this change point */
+       };
+       static struct change_member change_point_list[2*E820_X_MAX] __initdata;
+       static struct change_member *change_point[2*E820_X_MAX] __initdata;
+       static struct e820entry *overlap_list[E820_X_MAX] __initdata;
+       static struct e820entry new_bios[E820_X_MAX] __initdata;
+       struct change_member *change_tmp;
+       unsigned long current_type, last_type;
+       unsigned long long last_addr;
+       int chgidx, still_changing;
+       int overlap_entries;
+       int new_bios_entry;
+       int old_nr, new_nr, chg_nr;
+       int i;
+
+       /* if there's only one memory region, don't bother */
+       if (*pnr_map < 2)
+               return -1;
+
+       old_nr = *pnr_map;
+       BUG_ON(old_nr > max_nr_map);
+
+       /* bail out if we find any unreasonable addresses in bios map */
+       for (i = 0; i < old_nr; i++)
+               if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
+                       return -1;
+
+       /* create pointers for initial change-point information (for sorting) */
+       for (i = 0; i < 2 * old_nr; i++)
+               change_point[i] = &change_point_list[i];
+
+       /* record all known change-points (starting and ending addresses),
+          omitting those that are for empty memory regions */
+       chgidx = 0;
+       for (i = 0; i < old_nr; i++)    {
+               if (biosmap[i].size != 0) {
+                       change_point[chgidx]->addr = biosmap[i].addr;
+                       change_point[chgidx++]->pbios = &biosmap[i];
+                       change_point[chgidx]->addr = biosmap[i].addr +
+                               biosmap[i].size;
+                       change_point[chgidx++]->pbios = &biosmap[i];
+               }
+       }
+       chg_nr = chgidx;
+
+       /* sort change-point list by memory addresses (low -> high) */
+       still_changing = 1;
+       while (still_changing)  {
+               still_changing = 0;
+               for (i = 1; i < chg_nr; i++)  {
+                       unsigned long long curaddr, lastaddr;
+                       unsigned long long curpbaddr, lastpbaddr;
+
+                       curaddr = change_point[i]->addr;
+                       lastaddr = change_point[i - 1]->addr;
+                       curpbaddr = change_point[i]->pbios->addr;
+                       lastpbaddr = change_point[i - 1]->pbios->addr;
+
+                       /*
+                        * swap entries, when:
+                        *
+                        * curaddr > lastaddr or
+                        * curaddr == lastaddr and curaddr == curpbaddr and
+                        * lastaddr != lastpbaddr
+                        */
+                       if (curaddr < lastaddr ||
+                           (curaddr == lastaddr && curaddr == curpbaddr &&
+                            lastaddr != lastpbaddr)) {
+                               change_tmp = change_point[i];
+                               change_point[i] = change_point[i-1];
+                               change_point[i-1] = change_tmp;
+                               still_changing = 1;
+                       }
+               }
+       }
+
+       /* create a new bios memory map, removing overlaps */
+       overlap_entries = 0;     /* number of entries in the overlap table */
+       new_bios_entry = 0;      /* index for creating new bios map entries */
+       last_type = 0;           /* start with undefined memory type */
+       last_addr = 0;           /* start with 0 as last starting address */
+
+       /* loop through change-points, determining affect on the new bios map */
+       for (chgidx = 0; chgidx < chg_nr; chgidx++) {
+               /* keep track of all overlapping bios entries */
+               if (change_point[chgidx]->addr ==
+                   change_point[chgidx]->pbios->addr) {
+                       /*
+                        * add map entry to overlap list (> 1 entry
+                        * implies an overlap)
+                        */
+                       overlap_list[overlap_entries++] =
+                               change_point[chgidx]->pbios;
+               } else {
+                       /*
+                        * remove entry from list (order independent,
+                        * so swap with last)
+                        */
+                       for (i = 0; i < overlap_entries; i++) {
+                               if (overlap_list[i] ==
+                                   change_point[chgidx]->pbios)
+                                       overlap_list[i] =
+                                               overlap_list[overlap_entries-1];
+                       }
+                       overlap_entries--;
+               }
+               /*
+                * if there are overlapping entries, decide which
+                * "type" to use (larger value takes precedence --
+                * 1=usable, 2,3,4,4+=unusable)
+                */
+               current_type = 0;
+               for (i = 0; i < overlap_entries; i++)
+                       if (overlap_list[i]->type > current_type)
+                               current_type = overlap_list[i]->type;
+               /*
+                * continue building up new bios map based on this
+                * information
+                */
+               if (current_type != last_type)  {
+                       if (last_type != 0)      {
+                               new_bios[new_bios_entry].size =
+                                       change_point[chgidx]->addr - last_addr;
+                               /*
+                                * move forward only if the new size
+                                * was non-zero
+                                */
+                               if (new_bios[new_bios_entry].size != 0)
+                                       /*
+                                        * no more space left for new
+                                        * bios entries ?
+                                        */
+                                       if (++new_bios_entry >= max_nr_map)
+                                               break;
+                       }
+                       if (current_type != 0)  {
+                               new_bios[new_bios_entry].addr =
+                                       change_point[chgidx]->addr;
+                               new_bios[new_bios_entry].type = current_type;
+                               last_addr = change_point[chgidx]->addr;
+                       }
+                       last_type = current_type;
+               }
+       }
+       /* retain count for new bios entries */
+       new_nr = new_bios_entry;
+
+       /* copy new bios mapping into original location */
+       memcpy(biosmap, new_bios, new_nr * sizeof(struct e820entry));
+       *pnr_map = new_nr;
+
+       return 0;
+}
+
+static int __init __append_e820_map(struct e820entry *biosmap, int nr_map)
+{
+       while (nr_map) {
+               u64 start = biosmap->addr;
+               u64 size = biosmap->size;
+               u64 end = start + size;
+               u32 type = biosmap->type;
+
+               /* Overflow in 64 bits? Ignore the memory map. */
+               if (start > end)
+                       return -1;
+
+               e820_add_region(start, size, type);
+
+               biosmap++;
+               nr_map--;
+       }
+       return 0;
+}
+
+/*
+ * Copy the BIOS e820 map into a safe place.
+ *
+ * Sanity-check it while we're at it..
+ *
+ * If we're lucky and live on a modern system, the setup code
+ * will have given us a memory map that we can use to properly
+ * set up memory.  If we aren't, we'll fake a memory map.
+ */
+static int __init append_e820_map(struct e820entry *biosmap, int nr_map)
+{
+       /* Only one memory region (or negative)? Ignore it */
+       if (nr_map < 2)
+               return -1;
+
+       return __append_e820_map(biosmap, nr_map);
+}
+
+static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
+                                       u64 size, unsigned old_type,
+                                       unsigned new_type)
+{
+       int i;
+       u64 real_updated_size = 0;
+
+       BUG_ON(old_type == new_type);
+
+       if (size > (ULLONG_MAX - start))
+               size = ULLONG_MAX - start;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820x->map[i];
+               u64 final_start, final_end;
+               if (ei->type != old_type)
+                       continue;
+               /* totally covered? */
+               if (ei->addr >= start &&
+                   (ei->addr + ei->size) <= (start + size)) {
+                       ei->type = new_type;
+                       real_updated_size += ei->size;
+                       continue;
+               }
+               /* partially covered */
+               final_start = max(start, ei->addr);
+               final_end = min(start + size, ei->addr + ei->size);
+               if (final_start >= final_end)
+                       continue;
+               e820_add_region(final_start, final_end - final_start,
+                                        new_type);
+               real_updated_size += final_end - final_start;
+
+               ei->size -= final_end - final_start;
+               if (ei->addr < final_start)
+                       continue;
+               ei->addr = final_end;
+       }
+       return real_updated_size;
+}
+
+u64 __init e820_update_range(u64 start, u64 size, unsigned old_type,
+                            unsigned new_type)
+{
+       return e820_update_range_map(&e820, start, size, old_type, new_type);
+}
+
+static u64 __init e820_update_range_saved(u64 start, u64 size,
+                                         unsigned old_type, unsigned new_type)
+{
+       return e820_update_range_map(&e820_saved, start, size, old_type,
+                                    new_type);
+}
+
+/* make e820 not cover the range */
+u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type,
+                            int checktype)
+{
+       int i;
+       u64 real_removed_size = 0;
+
+       if (size > (ULLONG_MAX - start))
+               size = ULLONG_MAX - start;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               u64 final_start, final_end;
+
+               if (checktype && ei->type != old_type)
+                       continue;
+               /* totally covered? */
+               if (ei->addr >= start &&
+                   (ei->addr + ei->size) <= (start + size)) {
+                       real_removed_size += ei->size;
+                       memset(ei, 0, sizeof(struct e820entry));
+                       continue;
+               }
+               /* partially covered */
+               final_start = max(start, ei->addr);
+               final_end = min(start + size, ei->addr + ei->size);
+               if (final_start >= final_end)
+                       continue;
+               real_removed_size += final_end - final_start;
+
+               ei->size -= final_end - final_start;
+               if (ei->addr < final_start)
+                       continue;
+               ei->addr = final_end;
+       }
+       return real_removed_size;
+}
+
+void __init update_e820(void)
+{
+       int nr_map;
+
+       nr_map = e820.nr_map;
+       if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map))
+               return;
+       e820.nr_map = nr_map;
+       printk(KERN_INFO "modified physical RAM map:\n");
+       e820_print_map("modified");
+}
+static void __init update_e820_saved(void)
+{
+       int nr_map;
+
+       nr_map = e820_saved.nr_map;
+       if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map))
+               return;
+       e820_saved.nr_map = nr_map;
+}
+#define MAX_GAP_END 0x100000000ull
+/*
+ * Search for a gap in the e820 memory space from start_addr to end_addr.
+ */
+__init int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
+               unsigned long start_addr, unsigned long long end_addr)
+{
+       unsigned long long last;
+       int i = e820.nr_map;
+       int found = 0;
+
+       last = (end_addr && end_addr < MAX_GAP_END) ? end_addr : MAX_GAP_END;
+
+       while (--i >= 0) {
+               unsigned long long start = e820.map[i].addr;
+               unsigned long long end = start + e820.map[i].size;
+
+               if (end < start_addr)
+                       continue;
+
+               /*
+                * Since "last" is at most 4GB, we know we'll
+                * fit in 32 bits if this condition is true
+                */
+               if (last > end) {
+                       unsigned long gap = last - end;
+
+                       if (gap >= *gapsize) {
+                               *gapsize = gap;
+                               *gapstart = end;
+                               found = 1;
+                       }
+               }
+               if (start < last)
+                       last = start;
+       }
+       return found;
+}
+
+/*
+ * Search for the biggest gap in the low 32 bits of the e820
+ * memory space.  We pass this space to PCI to assign MMIO resources
+ * for hotplug or unconfigured devices in.
+ * Hopefully the BIOS let enough space left.
+ */
+__init void e820_setup_gap(void)
+{
+       unsigned long gapstart, gapsize, round;
+       int found;
+
+       gapstart = 0x10000000;
+       gapsize = 0x400000;
+       found  = e820_search_gap(&gapstart, &gapsize, 0, MAX_GAP_END);
+
+#ifdef CONFIG_X86_64
+       if (!found) {
+               gapstart = (max_pfn << PAGE_SHIFT) + 1024*1024;
+               printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit "
+                      "address range\n"
+                      KERN_ERR "PCI: Unassigned devices with 32bit resource "
+                      "registers may break!\n");
+       }
+#endif
+
+       /*
+        * See how much we want to round up: start off with
+        * rounding to the next 1MB area.
+        */
+       round = 0x100000;
+       while ((gapsize >> 4) > round)
+               round += round;
+       /* Fun with two's complement */
+       pci_mem_start = (gapstart + round) & -round;
+
+       printk(KERN_INFO
+              "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
+              pci_mem_start, gapstart, gapsize);
+}
+
+/**
+ * Because of the size limitation of struct boot_params, only first
+ * 128 E820 memory entries are passed to kernel via
+ * boot_params.e820_map, others are passed via SETUP_E820_EXT node of
+ * linked list of struct setup_data, which is parsed here.
+ */
+void __init parse_e820_ext(struct setup_data *sdata, unsigned long pa_data)
+{
+       u32 map_len;
+       int entries;
+       struct e820entry *extmap;
+
+       entries = sdata->len / sizeof(struct e820entry);
+       map_len = sdata->len + sizeof(struct setup_data);
+       if (map_len > PAGE_SIZE)
+               sdata = early_ioremap(pa_data, map_len);
+       extmap = (struct e820entry *)(sdata->data);
+       __append_e820_map(extmap, entries);
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+       if (map_len > PAGE_SIZE)
+               early_iounmap(sdata, map_len);
+       printk(KERN_INFO "extended physical RAM map:\n");
+       e820_print_map("extended");
+}
+
+#if defined(CONFIG_X86_64) || \
+       (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))
+/**
+ * Find the ranges of physical addresses that do not correspond to
+ * e820 RAM areas and mark the corresponding pages as nosave for
+ * hibernation (32 bit) or software suspend and suspend to RAM (64 bit).
+ *
+ * This function requires the e820 map to be sorted and without any
+ * overlapping entries and assumes the first e820 area to be RAM.
+ */
+void __init e820_mark_nosave_regions(unsigned long limit_pfn)
+{
+       int i;
+       unsigned long pfn;
+
+       pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size);
+       for (i = 1; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+
+               if (pfn < PFN_UP(ei->addr))
+                       register_nosave_region(pfn, PFN_UP(ei->addr));
+
+               pfn = PFN_DOWN(ei->addr + ei->size);
+               if (ei->type != E820_RAM && ei->type != E820_RESERVED_KERN)
+                       register_nosave_region(PFN_UP(ei->addr), pfn);
+
+               if (pfn >= limit_pfn)
+                       break;
+       }
+}
+#endif
+
+/*
+ * Early reserved memory areas.
+ */
+#define MAX_EARLY_RES 20
+
+struct early_res {
+       u64 start, end;
+       char name[16];
+       char overlap_ok;
+};
+static struct early_res early_res[MAX_EARLY_RES] __initdata = {
+       { 0, PAGE_SIZE, "BIOS data page" },     /* BIOS data page */
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_TRAMPOLINE)
+       { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" },
+#endif
+#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
+       /*
+        * But first pinch a few for the stack/trampoline stuff
+        * FIXME: Don't need the extra page at 4K, but need to fix
+        * trampoline before removing it. (see the GDT stuff)
+        */
+       { PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE" },
+       /*
+        * Has to be in very low memory so we can execute
+        * real-mode AP code.
+        */
+       { TRAMPOLINE_BASE, TRAMPOLINE_BASE + PAGE_SIZE, "TRAMPOLINE" },
+#endif
+       {}
+};
+
+static int __init find_overlapped_early(u64 start, u64 end)
+{
+       int i;
+       struct early_res *r;
+
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+               r = &early_res[i];
+               if (end > r->start && start < r->end)
+                       break;
+       }
+
+       return i;
+}
+
+/*
+ * Drop the i-th range from the early reservation map,
+ * by copying any higher ranges down one over it, and
+ * clearing what had been the last slot.
+ */
+static void __init drop_range(int i)
+{
+       int j;
+
+       for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++)
+               ;
+
+       memmove(&early_res[i], &early_res[i + 1],
+              (j - 1 - i) * sizeof(struct early_res));
+
+       early_res[j - 1].end = 0;
+}
+
+/*
+ * Split any existing ranges that:
+ *  1) are marked 'overlap_ok', and
+ *  2) overlap with the stated range [start, end)
+ * into whatever portion (if any) of the existing range is entirely
+ * below or entirely above the stated range.  Drop the portion
+ * of the existing range that overlaps with the stated range,
+ * which will allow the caller of this routine to then add that
+ * stated range without conflicting with any existing range.
+ */
+static void __init drop_overlaps_that_are_ok(u64 start, u64 end)
+{
+       int i;
+       struct early_res *r;
+       u64 lower_start, lower_end;
+       u64 upper_start, upper_end;
+       char name[16];
+
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+               r = &early_res[i];
+
+               /* Continue past non-overlapping ranges */
+               if (end <= r->start || start >= r->end)
+                       continue;
+
+               /*
+                * Leave non-ok overlaps as is; let caller
+                * panic "Overlapping early reservations"
+                * when it hits this overlap.
+                */
+               if (!r->overlap_ok)
+                       return;
+
+               /*
+                * We have an ok overlap.  We will drop it from the early
+                * reservation map, and add back in any non-overlapping
+                * portions (lower or upper) as separate, overlap_ok,
+                * non-overlapping ranges.
+                */
+
+               /* 1. Note any non-overlapping (lower or upper) ranges. */
+               strncpy(name, r->name, sizeof(name) - 1);
+
+               lower_start = lower_end = 0;
+               upper_start = upper_end = 0;
+               if (r->start < start) {
+                       lower_start = r->start;
+                       lower_end = start;
+               }
+               if (r->end > end) {
+                       upper_start = end;
+                       upper_end = r->end;
+               }
+
+               /* 2. Drop the original ok overlapping range */
+               drop_range(i);
+
+               i--;            /* resume for-loop on copied down entry */
+
+               /* 3. Add back in any non-overlapping ranges. */
+               if (lower_end)
+                       reserve_early_overlap_ok(lower_start, lower_end, name);
+               if (upper_end)
+                       reserve_early_overlap_ok(upper_start, upper_end, name);
+       }
+}
+
+static void __init __reserve_early(u64 start, u64 end, char *name,
+                                               int overlap_ok)
+{
+       int i;
+       struct early_res *r;
+
+       i = find_overlapped_early(start, end);
+       if (i >= MAX_EARLY_RES)
+               panic("Too many early reservations");
+       r = &early_res[i];
+       if (r->end)
+               panic("Overlapping early reservations "
+                     "%llx-%llx %s to %llx-%llx %s\n",
+                     start, end - 1, name?name:"", r->start,
+                     r->end - 1, r->name);
+       r->start = start;
+       r->end = end;
+       r->overlap_ok = overlap_ok;
+       if (name)
+               strncpy(r->name, name, sizeof(r->name) - 1);
+}
+
+/*
+ * A few early reservtations come here.
+ *
+ * The 'overlap_ok' in the name of this routine does -not- mean it
+ * is ok for these reservations to overlap an earlier reservation.
+ * Rather it means that it is ok for subsequent reservations to
+ * overlap this one.
+ *
+ * Use this entry point to reserve early ranges when you are doing
+ * so out of "Paranoia", reserving perhaps more memory than you need,
+ * just in case, and don't mind a subsequent overlapping reservation
+ * that is known to be needed.
+ *
+ * The drop_overlaps_that_are_ok() call here isn't really needed.
+ * It would be needed if we had two colliding 'overlap_ok'
+ * reservations, so that the second such would not panic on the
+ * overlap with the first.  We don't have any such as of this
+ * writing, but might as well tolerate such if it happens in
+ * the future.
+ */
+void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
+{
+       drop_overlaps_that_are_ok(start, end);
+       __reserve_early(start, end, name, 1);
+}
+
+/*
+ * Most early reservations come here.
+ *
+ * We first have drop_overlaps_that_are_ok() drop any pre-existing
+ * 'overlap_ok' ranges, so that we can then reserve this memory
+ * range without risk of panic'ing on an overlapping overlap_ok
+ * early reservation.
+ */
+void __init reserve_early(u64 start, u64 end, char *name)
+{
+       drop_overlaps_that_are_ok(start, end);
+       __reserve_early(start, end, name, 0);
+}
+
+void __init free_early(u64 start, u64 end)
+{
+       struct early_res *r;
+       int i;
+
+       i = find_overlapped_early(start, end);
+       r = &early_res[i];
+       if (i >= MAX_EARLY_RES || r->end != end || r->start != start)
+               panic("free_early on not reserved area: %llx-%llx!",
+                        start, end - 1);
+
+       drop_range(i);
+}
+
+void __init early_res_to_bootmem(u64 start, u64 end)
+{
+       int i, count;
+       u64 final_start, final_end;
+
+       count  = 0;
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++)
+               count++;
+
+       printk(KERN_INFO "(%d early reservations) ==> bootmem\n", count);
+       for (i = 0; i < count; i++) {
+               struct early_res *r = &early_res[i];
+               printk(KERN_INFO "  #%d [%010llx - %010llx] %16s", i,
+                       r->start, r->end, r->name);
+               final_start = max(start, r->start);
+               final_end = min(end, r->end);
+               if (final_start >= final_end) {
+                       printk(KERN_CONT "\n");
+                       continue;
+               }
+               printk(KERN_CONT " ==> [%010llx - %010llx]\n",
+                       final_start, final_end);
+               reserve_bootmem_generic(final_start, final_end - final_start,
+                               BOOTMEM_DEFAULT);
+       }
+}
+
+/* Check for already reserved areas */
+static inline int __init bad_addr(u64 *addrp, u64 size, u64 align)
+{
+       int i;
+       u64 addr = *addrp;
+       int changed = 0;
+       struct early_res *r;
+again:
+       i = find_overlapped_early(addr, addr + size);
+       r = &early_res[i];
+       if (i < MAX_EARLY_RES && r->end) {
+               *addrp = addr = round_up(r->end, align);
+               changed = 1;
+               goto again;
+       }
+       return changed;
+}
+
+/* Check for already reserved areas */
+static inline int __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align)
+{
+       int i;
+       u64 addr = *addrp, last;
+       u64 size = *sizep;
+       int changed = 0;
+again:
+       last = addr + size;
+       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
+               struct early_res *r = &early_res[i];
+               if (last > r->start && addr < r->start) {
+                       size = r->start - addr;
+                       changed = 1;
+                       goto again;
+               }
+               if (last > r->end && addr < r->end) {
+                       addr = round_up(r->end, align);
+                       size = last - addr;
+                       changed = 1;
+                       goto again;
+               }
+               if (last <= r->end && addr >= r->start) {
+                       (*sizep)++;
+                       return 0;
+               }
+       }
+       if (changed) {
+               *addrp = addr;
+               *sizep = size;
+       }
+       return changed;
+}
+
+/*
+ * Find a free area with specified alignment in a specific range.
+ */
+u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align)
+{
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               u64 addr, last;
+               u64 ei_last;
+
+               if (ei->type != E820_RAM)
+                       continue;
+               addr = round_up(ei->addr, align);
+               ei_last = ei->addr + ei->size;
+               if (addr < start)
+                       addr = round_up(start, align);
+               if (addr >= ei_last)
+                       continue;
+               while (bad_addr(&addr, size, align) && addr+size <= ei_last)
+                       ;
+               last = addr + size;
+               if (last > ei_last)
+                       continue;
+               if (last > end)
+                       continue;
+               return addr;
+       }
+       return -1ULL;
+}
+
+/*
+ * Find next free range after *start
+ */
+u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
+{
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               u64 addr, last;
+               u64 ei_last;
+
+               if (ei->type != E820_RAM)
+                       continue;
+               addr = round_up(ei->addr, align);
+               ei_last = ei->addr + ei->size;
+               if (addr < start)
+                       addr = round_up(start, align);
+               if (addr >= ei_last)
+                       continue;
+               *sizep = ei_last - addr;
+               while (bad_addr_size(&addr, sizep, align) &&
+                       addr + *sizep <= ei_last)
+                       ;
+               last = addr + *sizep;
+               if (last > ei_last)
+                       continue;
+               return addr;
+       }
+       return -1UL;
+
+}
+
+/*
+ * pre allocated 4k and reserved it in e820
+ */
+u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
+{
+       u64 size = 0;
+       u64 addr;
+       u64 start;
+
+       start = startt;
+       while (size < sizet)
+               start = find_e820_area_size(start, &size, align);
+
+       if (size < sizet)
+               return 0;
+
+       addr = round_down(start + size - sizet, align);
+       e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
+       e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
+       printk(KERN_INFO "update e820 for early_reserve_e820\n");
+       update_e820();
+       update_e820_saved();
+
+       return addr;
+}
+
+#ifdef CONFIG_X86_32
+# ifdef CONFIG_X86_PAE
+#  define MAX_ARCH_PFN         (1ULL<<(36-PAGE_SHIFT))
+# else
+#  define MAX_ARCH_PFN         (1ULL<<(32-PAGE_SHIFT))
+# endif
+#else /* CONFIG_X86_32 */
+# define MAX_ARCH_PFN MAXMEM>>PAGE_SHIFT
+#endif
+
+/*
+ * Find the highest page frame number we have available
+ */
+static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
+{
+       int i;
+       unsigned long last_pfn = 0;
+       unsigned long max_arch_pfn = MAX_ARCH_PFN;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+               unsigned long start_pfn;
+               unsigned long end_pfn;
+
+               if (ei->type != type)
+                       continue;
+
+               start_pfn = ei->addr >> PAGE_SHIFT;
+               end_pfn = (ei->addr + ei->size) >> PAGE_SHIFT;
+
+               if (start_pfn >= limit_pfn)
+                       continue;
+               if (end_pfn > limit_pfn) {
+                       last_pfn = limit_pfn;
+                       break;
+               }
+               if (end_pfn > last_pfn)
+                       last_pfn = end_pfn;
+       }
+
+       if (last_pfn > max_arch_pfn)
+               last_pfn = max_arch_pfn;
+
+       printk(KERN_INFO "last_pfn = %#lx max_arch_pfn = %#lx\n",
+                        last_pfn, max_arch_pfn);
+       return last_pfn;
+}
+unsigned long __init e820_end_of_ram_pfn(void)
+{
+       return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
+}
+
+unsigned long __init e820_end_of_low_ram_pfn(void)
+{
+       return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
+}
+/*
+ * Finds an active region in the address range from start_pfn to last_pfn and
+ * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
+ */
+int __init e820_find_active_region(const struct e820entry *ei,
+                                 unsigned long start_pfn,
+                                 unsigned long last_pfn,
+                                 unsigned long *ei_startpfn,
+                                 unsigned long *ei_endpfn)
+{
+       u64 align = PAGE_SIZE;
+
+       *ei_startpfn = round_up(ei->addr, align) >> PAGE_SHIFT;
+       *ei_endpfn = round_down(ei->addr + ei->size, align) >> PAGE_SHIFT;
+
+       /* Skip map entries smaller than a page */
+       if (*ei_startpfn >= *ei_endpfn)
+               return 0;
+
+       /* Skip if map is outside the node */
+       if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
+                                   *ei_startpfn >= last_pfn)
+               return 0;
+
+       /* Check for overlaps */
+       if (*ei_startpfn < start_pfn)
+               *ei_startpfn = start_pfn;
+       if (*ei_endpfn > last_pfn)
+               *ei_endpfn = last_pfn;
+
+       return 1;
+}
+
+/* Walk the e820 map and register active regions within a node */
+void __init e820_register_active_regions(int nid, unsigned long start_pfn,
+                                        unsigned long last_pfn)
+{
+       unsigned long ei_startpfn;
+       unsigned long ei_endpfn;
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++)
+               if (e820_find_active_region(&e820.map[i],
+                                           start_pfn, last_pfn,
+                                           &ei_startpfn, &ei_endpfn))
+                       add_active_range(nid, ei_startpfn, ei_endpfn);
+}
+
+/*
+ * Find the hole size (in bytes) in the memory range.
+ * @start: starting address of the memory range to scan
+ * @end: ending address of the memory range to scan
+ */
+u64 __init e820_hole_size(u64 start, u64 end)
+{
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long last_pfn = end >> PAGE_SHIFT;
+       unsigned long ei_startpfn, ei_endpfn, ram = 0;
+       int i;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               if (e820_find_active_region(&e820.map[i],
+                                           start_pfn, last_pfn,
+                                           &ei_startpfn, &ei_endpfn))
+                       ram += ei_endpfn - ei_startpfn;
+       }
+       return end - start - ((u64)ram << PAGE_SHIFT);
+}
+
+static void early_panic(char *msg)
+{
+       early_printk(msg);
+       panic(msg);
+}
+
+static int userdef __initdata;
+
+/* "mem=nopentium" disables the 4MB page tables. */
+static int __init parse_memopt(char *p)
+{
+       u64 mem_size;
+
+       if (!p)
+               return -EINVAL;
+
+#ifdef CONFIG_X86_32
+       if (!strcmp(p, "nopentium")) {
+               setup_clear_cpu_cap(X86_FEATURE_PSE);
+               return 0;
+       }
+#endif
+
+       userdef = 1;
+       mem_size = memparse(p, &p);
+       e820_remove_range(mem_size, ULLONG_MAX - mem_size, E820_RAM, 1);
+
+       return 0;
+}
+early_param("mem", parse_memopt);
+
+static int __init parse_memmap_opt(char *p)
+{
+       char *oldp;
+       u64 start_at, mem_size;
+
+       if (!p)
+               return -EINVAL;
+
+       if (!strcmp(p, "exactmap")) {
+#ifdef CONFIG_CRASH_DUMP
+               /*
+                * If we are doing a crash dump, we still need to know
+                * the real mem size before original memory map is
+                * reset.
+                */
+               saved_max_pfn = e820_end_of_ram_pfn();
+#endif
+               e820.nr_map = 0;
+               userdef = 1;
+               return 0;
+       }
+
+       oldp = p;
+       mem_size = memparse(p, &p);
+       if (p == oldp)
+               return -EINVAL;
+
+       userdef = 1;
+       if (*p == '@') {
+               start_at = memparse(p+1, &p);
+               e820_add_region(start_at, mem_size, E820_RAM);
+       } else if (*p == '#') {
+               start_at = memparse(p+1, &p);
+               e820_add_region(start_at, mem_size, E820_ACPI);
+       } else if (*p == '$') {
+               start_at = memparse(p+1, &p);
+               e820_add_region(start_at, mem_size, E820_RESERVED);
+       } else
+               e820_remove_range(mem_size, ULLONG_MAX - mem_size, E820_RAM, 1);
+
+       return *p == '\0' ? 0 : -EINVAL;
+}
+early_param("memmap", parse_memmap_opt);
+
+void __init finish_e820_parsing(void)
+{
+       if (userdef) {
+               int nr = e820.nr_map;
+
+               if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0)
+                       early_panic("Invalid user supplied memory map");
+               e820.nr_map = nr;
+
+               printk(KERN_INFO "user-defined physical RAM map:\n");
+               e820_print_map("user");
+       }
+}
+
+static inline const char *e820_type_to_string(int e820_type)
+{
+       switch (e820_type) {
+       case E820_RESERVED_KERN:
+       case E820_RAM:  return "System RAM";
+       case E820_ACPI: return "ACPI Tables";
+       case E820_NVS:  return "ACPI Non-volatile Storage";
+       default:        return "reserved";
+       }
+}
+
+/*
+ * Mark e820 reserved areas as busy for the resource manager.
+ */
+void __init e820_reserve_resources(void)
+{
+       int i;
+       struct resource *res;
+       u64 end;
+
+       res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
+       for (i = 0; i < e820.nr_map; i++) {
+               end = e820.map[i].addr + e820.map[i].size - 1;
+#ifndef CONFIG_RESOURCES_64BIT
+               if (end > 0x100000000ULL) {
+                       res++;
+                       continue;
+               }
+#endif
+               res->name = e820_type_to_string(e820.map[i].type);
+               res->start = e820.map[i].addr;
+               res->end = end;
+
+               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               insert_resource(&iomem_resource, res);
+               res++;
+       }
+
+       for (i = 0; i < e820_saved.nr_map; i++) {
+               struct e820entry *entry = &e820_saved.map[i];
+               firmware_map_add_early(entry->addr,
+                       entry->addr + entry->size - 1,
+                       e820_type_to_string(entry->type));
+       }
+}
+
+/*
+ * Non-standard memory setup can be specified via this quirk:
+ */
+char * (*arch_memory_setup_quirk)(void);
+
+char *__init default_machine_specific_memory_setup(void)
+{
+       char *who = "BIOS-e820";
+       int new_nr;
+       /*
+        * Try to copy the BIOS-supplied E820-map.
+        *
+        * Otherwise fake a memory map; one section from 0k->640k,
+        * the next section from 1mb->appropriate_mem_k
+        */
+       new_nr = boot_params.e820_entries;
+       sanitize_e820_map(boot_params.e820_map,
+                       ARRAY_SIZE(boot_params.e820_map),
+                       &new_nr);
+       boot_params.e820_entries = new_nr;
+       if (append_e820_map(boot_params.e820_map, boot_params.e820_entries)
+         < 0) {
+               u64 mem_size;
+
+               /* compare results from other methods and take the greater */
+               if (boot_params.alt_mem_k
+                   < boot_params.screen_info.ext_mem_k) {
+                       mem_size = boot_params.screen_info.ext_mem_k;
+                       who = "BIOS-88";
+               } else {
+                       mem_size = boot_params.alt_mem_k;
+                       who = "BIOS-e801";
+               }
+
+               e820.nr_map = 0;
+               e820_add_region(0, LOWMEMSIZE(), E820_RAM);
+               e820_add_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+       }
+
+       /* In case someone cares... */
+       return who;
+}
+
+char *__init __attribute__((weak)) machine_specific_memory_setup(void)
+{
+       if (arch_memory_setup_quirk) {
+               char *who = arch_memory_setup_quirk();
+
+               if (who)
+                       return who;
+       }
+       return default_machine_specific_memory_setup();
+}
+
+/* Overridden in paravirt.c if CONFIG_PARAVIRT */
+char * __init __attribute__((weak)) memory_setup(void)
+{
+       return machine_specific_memory_setup();
+}
+
+void __init setup_memory_map(void)
+{
+       char *who;
+
+       who = memory_setup();
+       memcpy(&e820_saved, &e820, sizeof(struct e820map));
+       printk(KERN_INFO "BIOS-provided physical RAM map:\n");
+       e820_print_map(who);
+}
+
+#ifdef CONFIG_X86_64
+int __init arch_get_ram_range(int slot, u64 *addr, u64 *size)
+{
+       int i;
+
+       if (slot < 0 || slot >= e820.nr_map)
+               return -1;
+       for (i = slot; i < e820.nr_map; i++) {
+               if (e820.map[i].type != E820_RAM)
+                       continue;
+               break;
+       }
+       if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT))
+               return -1;
+       *addr = e820.map[i].addr;
+       *size = min_t(u64, e820.map[i].size + e820.map[i].addr,
+               max_pfn << PAGE_SHIFT) - *addr;
+       return i + 1;
+}
+#endif
diff --git a/arch/x86/kernel/e820_32.c b/arch/x86/kernel/e820_32.c
deleted file mode 100644 (file)
index ed733e7..0000000
+++ /dev/null
@@ -1,775 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/kexec.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/pfn.h>
-#include <linux/uaccess.h>
-#include <linux/suspend.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/e820.h>
-#include <asm/setup.h>
-
-struct e820map e820;
-struct change_member {
-       struct e820entry *pbios; /* pointer to original bios entry */
-       unsigned long long addr; /* address for this change point */
-};
-static struct change_member change_point_list[2*E820MAX] __initdata;
-static struct change_member *change_point[2*E820MAX] __initdata;
-static struct e820entry *overlap_list[E820MAX] __initdata;
-static struct e820entry new_bios[E820MAX] __initdata;
-/* For PCI or other memory-mapped resources */
-unsigned long pci_mem_start = 0x10000000;
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_mem_start);
-#endif
-extern int user_defined_memmap;
-
-static struct resource system_rom_resource = {
-       .name   = "System ROM",
-       .start  = 0xf0000,
-       .end    = 0xfffff,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource extension_rom_resource = {
-       .name   = "Extension ROM",
-       .start  = 0xe0000,
-       .end    = 0xeffff,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource adapter_rom_resources[] = { {
-       .name   = "Adapter ROM",
-       .start  = 0xc8000,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-       .name   = "Adapter ROM",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-       .name   = "Adapter ROM",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-       .name   = "Adapter ROM",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-       .name   = "Adapter ROM",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-       .name   = "Adapter ROM",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-} };
-
-static struct resource video_rom_resource = {
-       .name   = "Video ROM",
-       .start  = 0xc0000,
-       .end    = 0xc7fff,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-#define ROMSIGNATURE 0xaa55
-
-static int __init romsignature(const unsigned char *rom)
-{
-       const unsigned short * const ptr = (const unsigned short *)rom;
-       unsigned short sig;
-
-       return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE;
-}
-
-static int __init romchecksum(const unsigned char *rom, unsigned long length)
-{
-       unsigned char sum, c;
-
-       for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--)
-               sum += c;
-       return !length && !sum;
-}
-
-static void __init probe_roms(void)
-{
-       const unsigned char *rom;
-       unsigned long start, length, upper;
-       unsigned char c;
-       int i;
-
-       /* video rom */
-       upper = adapter_rom_resources[0].start;
-       for (start = video_rom_resource.start; start < upper; start += 2048) {
-               rom = isa_bus_to_virt(start);
-               if (!romsignature(rom))
-                       continue;
-
-               video_rom_resource.start = start;
-
-               if (probe_kernel_address(rom + 2, c) != 0)
-                       continue;
-
-               /* 0 < length <= 0x7f * 512, historically */
-               length = c * 512;
-
-               /* if checksum okay, trust length byte */
-               if (length && romchecksum(rom, length))
-                       video_rom_resource.end = start + length - 1;
-
-               request_resource(&iomem_resource, &video_rom_resource);
-               break;
-       }
-
-       start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
-       if (start < upper)
-               start = upper;
-
-       /* system rom */
-       request_resource(&iomem_resource, &system_rom_resource);
-       upper = system_rom_resource.start;
-
-       /* check for extension rom (ignore length byte!) */
-       rom = isa_bus_to_virt(extension_rom_resource.start);
-       if (romsignature(rom)) {
-               length = extension_rom_resource.end - extension_rom_resource.start + 1;
-               if (romchecksum(rom, length)) {
-                       request_resource(&iomem_resource, &extension_rom_resource);
-                       upper = extension_rom_resource.start;
-               }
-       }
-
-       /* check for adapter roms on 2k boundaries */
-       for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
-               rom = isa_bus_to_virt(start);
-               if (!romsignature(rom))
-                       continue;
-
-               if (probe_kernel_address(rom + 2, c) != 0)
-                       continue;
-
-               /* 0 < length <= 0x7f * 512, historically */
-               length = c * 512;
-
-               /* but accept any length that fits if checksum okay */
-               if (!length || start + length > upper || !romchecksum(rom, length))
-                       continue;
-
-               adapter_rom_resources[i].start = start;
-               adapter_rom_resources[i].end = start + length - 1;
-               request_resource(&iomem_resource, &adapter_rom_resources[i]);
-
-               start = adapter_rom_resources[i++].end & ~2047UL;
-       }
-}
-
-/*
- * Request address space for all standard RAM and ROM resources
- * and also for regions reported as reserved by the e820.
- */
-void __init init_iomem_resources(struct resource *code_resource,
-               struct resource *data_resource,
-               struct resource *bss_resource)
-{
-       int i;
-
-       probe_roms();
-       for (i = 0; i < e820.nr_map; i++) {
-               struct resource *res;
-#ifndef CONFIG_RESOURCES_64BIT
-               if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
-                       continue;
-#endif
-               res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
-               switch (e820.map[i].type) {
-               case E820_RAM:  res->name = "System RAM"; break;
-               case E820_ACPI: res->name = "ACPI Tables"; break;
-               case E820_NVS:  res->name = "ACPI Non-volatile Storage"; break;
-               default:        res->name = "reserved";
-               }
-               res->start = e820.map[i].addr;
-               res->end = res->start + e820.map[i].size - 1;
-               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               if (request_resource(&iomem_resource, res)) {
-                       kfree(res);
-                       continue;
-               }
-               if (e820.map[i].type == E820_RAM) {
-                       /*
-                        *  We don't know which RAM region contains kernel data,
-                        *  so we try it repeatedly and let the resource manager
-                        *  test it.
-                        */
-                       request_resource(res, code_resource);
-                       request_resource(res, data_resource);
-                       request_resource(res, bss_resource);
-#ifdef CONFIG_KEXEC
-                       if (crashk_res.start != crashk_res.end)
-                               request_resource(res, &crashk_res);
-#endif
-               }
-       }
-}
-
-#if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION)
-/**
- * e820_mark_nosave_regions - Find the ranges of physical addresses that do not
- * correspond to e820 RAM areas and mark the corresponding pages as nosave for
- * hibernation.
- *
- * This function requires the e820 map to be sorted and without any
- * overlapping entries and assumes the first e820 area to be RAM.
- */
-void __init e820_mark_nosave_regions(void)
-{
-       int i;
-       unsigned long pfn;
-
-       pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size);
-       for (i = 1; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-
-               if (pfn < PFN_UP(ei->addr))
-                       register_nosave_region(pfn, PFN_UP(ei->addr));
-
-               pfn = PFN_DOWN(ei->addr + ei->size);
-               if (ei->type != E820_RAM)
-                       register_nosave_region(PFN_UP(ei->addr), pfn);
-
-               if (pfn >= max_low_pfn)
-                       break;
-       }
-}
-#endif
-
-void __init add_memory_region(unsigned long long start,
-                             unsigned long long size, int type)
-{
-       int x;
-
-       x = e820.nr_map;
-
-       if (x == E820MAX) {
-               printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
-               return;
-       }
-
-       e820.map[x].addr = start;
-       e820.map[x].size = size;
-       e820.map[x].type = type;
-       e820.nr_map++;
-} /* add_memory_region */
-
-/*
- * Sanitize the BIOS e820 map.
- *
- * Some e820 responses include overlapping entries.  The following
- * replaces the original e820 map with a new one, removing overlaps.
- *
- */
-int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
-{
-       struct change_member *change_tmp;
-       unsigned long current_type, last_type;
-       unsigned long long last_addr;
-       int chgidx, still_changing;
-       int overlap_entries;
-       int new_bios_entry;
-       int old_nr, new_nr, chg_nr;
-       int i;
-
-       /*
-               Visually we're performing the following (1,2,3,4 = memory types)...
-
-               Sample memory map (w/overlaps):
-                  ____22__________________
-                  ______________________4_
-                  ____1111________________
-                  _44_____________________
-                  11111111________________
-                  ____________________33__
-                  ___________44___________
-                  __________33333_________
-                  ______________22________
-                  ___________________2222_
-                  _________111111111______
-                  _____________________11_
-                  _________________4______
-
-               Sanitized equivalent (no overlap):
-                  1_______________________
-                  _44_____________________
-                  ___1____________________
-                  ____22__________________
-                  ______11________________
-                  _________1______________
-                  __________3_____________
-                  ___________44___________
-                  _____________33_________
-                  _______________2________
-                  ________________1_______
-                  _________________4______
-                  ___________________2____
-                  ____________________33__
-                  ______________________4_
-       */
-       /* if there's only one memory region, don't bother */
-       if (*pnr_map < 2) {
-               return -1;
-       }
-
-       old_nr = *pnr_map;
-
-       /* bail out if we find any unreasonable addresses in bios map */
-       for (i=0; i<old_nr; i++)
-               if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) {
-                       return -1;
-               }
-
-       /* create pointers for initial change-point information (for sorting) */
-       for (i=0; i < 2*old_nr; i++)
-               change_point[i] = &change_point_list[i];
-
-       /* record all known change-points (starting and ending addresses),
-          omitting those that are for empty memory regions */
-       chgidx = 0;
-       for (i=0; i < old_nr; i++)      {
-               if (biosmap[i].size != 0) {
-                       change_point[chgidx]->addr = biosmap[i].addr;
-                       change_point[chgidx++]->pbios = &biosmap[i];
-                       change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
-                       change_point[chgidx++]->pbios = &biosmap[i];
-               }
-       }
-       chg_nr = chgidx;        /* true number of change-points */
-
-       /* sort change-point list by memory addresses (low -> high) */
-       still_changing = 1;
-       while (still_changing)  {
-               still_changing = 0;
-               for (i=1; i < chg_nr; i++)  {
-                       /* if <current_addr> > <last_addr>, swap */
-                       /* or, if current=<start_addr> & last=<end_addr>, swap */
-                       if ((change_point[i]->addr < change_point[i-1]->addr) ||
-                               ((change_point[i]->addr == change_point[i-1]->addr) &&
-                                (change_point[i]->addr == change_point[i]->pbios->addr) &&
-                                (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
-                          )
-                       {
-                               change_tmp = change_point[i];
-                               change_point[i] = change_point[i-1];
-                               change_point[i-1] = change_tmp;
-                               still_changing=1;
-                       }
-               }
-       }
-
-       /* create a new bios memory map, removing overlaps */
-       overlap_entries=0;       /* number of entries in the overlap table */
-       new_bios_entry=0;        /* index for creating new bios map entries */
-       last_type = 0;           /* start with undefined memory type */
-       last_addr = 0;           /* start with 0 as last starting address */
-       /* loop through change-points, determining affect on the new bios map */
-       for (chgidx=0; chgidx < chg_nr; chgidx++)
-       {
-               /* keep track of all overlapping bios entries */
-               if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
-               {
-                       /* add map entry to overlap list (> 1 entry implies an overlap) */
-                       overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
-               }
-               else
-               {
-                       /* remove entry from list (order independent, so swap with last) */
-                       for (i=0; i<overlap_entries; i++)
-                       {
-                               if (overlap_list[i] == change_point[chgidx]->pbios)
-                                       overlap_list[i] = overlap_list[overlap_entries-1];
-                       }
-                       overlap_entries--;
-               }
-               /* if there are overlapping entries, decide which "type" to use */
-               /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
-               current_type = 0;
-               for (i=0; i<overlap_entries; i++)
-                       if (overlap_list[i]->type > current_type)
-                               current_type = overlap_list[i]->type;
-               /* continue building up new bios map based on this information */
-               if (current_type != last_type)  {
-                       if (last_type != 0)      {
-                               new_bios[new_bios_entry].size =
-                                       change_point[chgidx]->addr - last_addr;
-                               /* move forward only if the new size was non-zero */
-                               if (new_bios[new_bios_entry].size != 0)
-                                       if (++new_bios_entry >= E820MAX)
-                                               break;  /* no more space left for new bios entries */
-                       }
-                       if (current_type != 0)  {
-                               new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
-                               new_bios[new_bios_entry].type = current_type;
-                               last_addr=change_point[chgidx]->addr;
-                       }
-                       last_type = current_type;
-               }
-       }
-       new_nr = new_bios_entry;   /* retain count for new bios entries */
-
-       /* copy new bios mapping into original location */
-       memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
-       *pnr_map = new_nr;
-
-       return 0;
-}
-
-/*
- * Copy the BIOS e820 map into a safe place.
- *
- * Sanity-check it while we're at it..
- *
- * If we're lucky and live on a modern system, the setup code
- * will have given us a memory map that we can use to properly
- * set up memory.  If we aren't, we'll fake a memory map.
- *
- * We check to see that the memory map contains at least 2 elements
- * before we'll use it, because the detection code in setup.S may
- * not be perfect and most every PC known to man has two memory
- * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
- * thinkpad 560x, for example, does not cooperate with the memory
- * detection code.)
- */
-int __init copy_e820_map(struct e820entry *biosmap, int nr_map)
-{
-       /* Only one memory region (or negative)? Ignore it */
-       if (nr_map < 2)
-               return -1;
-
-       do {
-               u64 start = biosmap->addr;
-               u64 size = biosmap->size;
-               u64 end = start + size;
-               u32 type = biosmap->type;
-
-               /* Overflow in 64 bits? Ignore the memory map. */
-               if (start > end)
-                       return -1;
-
-               add_memory_region(start, size, type);
-       } while (biosmap++, --nr_map);
-
-       return 0;
-}
-
-/*
- * Find the highest page frame number we have available
- */
-void __init propagate_e820_map(void)
-{
-       int i;
-
-       max_pfn = 0;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long start, end;
-               /* RAM? */
-               if (e820.map[i].type != E820_RAM)
-                       continue;
-               start = PFN_UP(e820.map[i].addr);
-               end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
-               if (start >= end)
-                       continue;
-               if (end > max_pfn)
-                       max_pfn = end;
-               memory_present(0, start, end);
-       }
-}
-
-/*
- * Register fully available low RAM pages with the bootmem allocator.
- */
-void __init register_bootmem_low_pages(unsigned long max_low_pfn)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long curr_pfn, last_pfn, size;
-               /*
-                * Reserve usable low memory
-                */
-               if (e820.map[i].type != E820_RAM)
-                       continue;
-               /*
-                * We are rounding up the start address of usable memory:
-                */
-               curr_pfn = PFN_UP(e820.map[i].addr);
-               if (curr_pfn >= max_low_pfn)
-                       continue;
-               /*
-                * ... and at the end of the usable range downwards:
-                */
-               last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
-
-               if (last_pfn > max_low_pfn)
-                       last_pfn = max_low_pfn;
-
-               /*
-                * .. finally, did all the rounding and playing
-                * around just make the area go away?
-                */
-               if (last_pfn <= curr_pfn)
-                       continue;
-
-               size = last_pfn - curr_pfn;
-               free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
-       }
-}
-
-void __init e820_register_memory(void)
-{
-       unsigned long gapstart, gapsize, round;
-       unsigned long long last;
-       int i;
-
-       /*
-        * Search for the biggest gap in the low 32 bits of the e820
-        * memory space.
-        */
-       last = 0x100000000ull;
-       gapstart = 0x10000000;
-       gapsize = 0x400000;
-       i = e820.nr_map;
-       while (--i >= 0) {
-               unsigned long long start = e820.map[i].addr;
-               unsigned long long end = start + e820.map[i].size;
-
-               /*
-                * Since "last" is at most 4GB, we know we'll
-                * fit in 32 bits if this condition is true
-                */
-               if (last > end) {
-                       unsigned long gap = last - end;
-
-                       if (gap > gapsize) {
-                               gapsize = gap;
-                               gapstart = end;
-                       }
-               }
-               if (start < last)
-                       last = start;
-       }
-
-       /*
-        * See how much we want to round up: start off with
-        * rounding to the next 1MB area.
-        */
-       round = 0x100000;
-       while ((gapsize >> 4) > round)
-               round += round;
-       /* Fun with two's complement */
-       pci_mem_start = (gapstart + round) & -round;
-
-       printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n",
-               pci_mem_start, gapstart, gapsize);
-}
-
-void __init print_memory_map(char *who)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               printk(" %s: %016Lx - %016Lx ", who,
-                       e820.map[i].addr,
-                       e820.map[i].addr + e820.map[i].size);
-               switch (e820.map[i].type) {
-               case E820_RAM:  printk("(usable)\n");
-                               break;
-               case E820_RESERVED:
-                               printk("(reserved)\n");
-                               break;
-               case E820_ACPI:
-                               printk("(ACPI data)\n");
-                               break;
-               case E820_NVS:
-                               printk("(ACPI NVS)\n");
-                               break;
-               default:        printk("type %u\n", e820.map[i].type);
-                               break;
-               }
-       }
-}
-
-void __init limit_regions(unsigned long long size)
-{
-       unsigned long long current_addr;
-       int i;
-
-       print_memory_map("limit_regions start");
-       for (i = 0; i < e820.nr_map; i++) {
-               current_addr = e820.map[i].addr + e820.map[i].size;
-               if (current_addr < size)
-                       continue;
-
-               if (e820.map[i].type != E820_RAM)
-                       continue;
-
-               if (e820.map[i].addr >= size) {
-                       /*
-                        * This region starts past the end of the
-                        * requested size, skip it completely.
-                        */
-                       e820.nr_map = i;
-               } else {
-                       e820.nr_map = i + 1;
-                       e820.map[i].size -= current_addr - size;
-               }
-               print_memory_map("limit_regions endfor");
-               return;
-       }
-       print_memory_map("limit_regions endfunc");
-}
-
-/*
- * This function checks if any part of the range <start,end> is mapped
- * with type.
- */
-int
-e820_any_mapped(u64 start, u64 end, unsigned type)
-{
-       int i;
-       for (i = 0; i < e820.nr_map; i++) {
-               const struct e820entry *ei = &e820.map[i];
-               if (type && ei->type != type)
-                       continue;
-               if (ei->addr >= end || ei->addr + ei->size <= start)
-                       continue;
-               return 1;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(e820_any_mapped);
-
- /*
-  * This function checks if the entire range <start,end> is mapped with type.
-  *
-  * Note: this function only works correct if the e820 table is sorted and
-  * not-overlapping, which is the case
-  */
-int __init
-e820_all_mapped(unsigned long s, unsigned long e, unsigned type)
-{
-       u64 start = s;
-       u64 end = e;
-       int i;
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               if (type && ei->type != type)
-                       continue;
-               /* is the region (part) in overlap with the current region ?*/
-               if (ei->addr >= end || ei->addr + ei->size <= start)
-                       continue;
-               /* if the region is at the beginning of <start,end> we move
-                * start to the end of the region since it's ok until there
-                */
-               if (ei->addr <= start)
-                       start = ei->addr + ei->size;
-               /* if start is now at or beyond end, we're done, full
-                * coverage */
-               if (start >= end)
-                       return 1; /* we're done */
-       }
-       return 0;
-}
-
-static int __init parse_memmap(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       if (strcmp(arg, "exactmap") == 0) {
-#ifdef CONFIG_CRASH_DUMP
-               /* If we are doing a crash dump, we
-                * still need to know the real mem
-                * size before original memory map is
-                * reset.
-                */
-               propagate_e820_map();
-               saved_max_pfn = max_pfn;
-#endif
-               e820.nr_map = 0;
-               user_defined_memmap = 1;
-       } else {
-               /* If the user specifies memory size, we
-                * limit the BIOS-provided memory map to
-                * that size. exactmap can be used to specify
-                * the exact map. mem=number can be used to
-                * trim the existing memory map.
-                */
-               unsigned long long start_at, mem_size;
-
-               mem_size = memparse(arg, &arg);
-               if (*arg == '@') {
-                       start_at = memparse(arg+1, &arg);
-                       add_memory_region(start_at, mem_size, E820_RAM);
-               } else if (*arg == '#') {
-                       start_at = memparse(arg+1, &arg);
-                       add_memory_region(start_at, mem_size, E820_ACPI);
-               } else if (*arg == '$') {
-                       start_at = memparse(arg+1, &arg);
-                       add_memory_region(start_at, mem_size, E820_RESERVED);
-               } else {
-                       limit_regions(mem_size);
-                       user_defined_memmap = 1;
-               }
-       }
-       return 0;
-}
-early_param("memmap", parse_memmap);
-void __init update_memory_range(u64 start, u64 size, unsigned old_type,
-                               unsigned new_type)
-{
-       int i;
-
-       BUG_ON(old_type == new_type);
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               u64 final_start, final_end;
-               if (ei->type != old_type)
-                       continue;
-               /* totally covered? */
-               if (ei->addr >= start && ei->size <= size) {
-                       ei->type = new_type;
-                       continue;
-               }
-               /* partially covered */
-               final_start = max(start, ei->addr);
-               final_end = min(start + size, ei->addr + ei->size);
-               if (final_start >= final_end)
-                       continue;
-               add_memory_region(final_start, final_end - final_start,
-                                        new_type);
-       }
-}
-void __init update_e820(void)
-{
-       u8 nr_map;
-
-       nr_map = e820.nr_map;
-       if (sanitize_e820_map(e820.map, &nr_map))
-               return;
-       e820.nr_map = nr_map;
-       printk(KERN_INFO "modified physical RAM map:\n");
-       print_memory_map("modified");
-}
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
deleted file mode 100644 (file)
index 124480c..0000000
+++ /dev/null
@@ -1,952 +0,0 @@
-/*
- * Handle the memory map.
- * The functions here do the job until bootmem takes over.
- *
- *  Getting sanitize_e820_map() in sync with i386 version by applying change:
- *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
- *     Alex Achenbach <xela@slit.de>, December 2002.
- *  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/kexec.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/suspend.h>
-#include <linux/pfn.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/e820.h>
-#include <asm/proto.h>
-#include <asm/setup.h>
-#include <asm/sections.h>
-#include <asm/kdebug.h>
-#include <asm/trampoline.h>
-
-struct e820map e820;
-
-/*
- * PFN of last memory page.
- */
-unsigned long end_pfn;
-
-/*
- * 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_pfn_mapped;
-
-/*
- * Last pfn which the user wants to use.
- */
-static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
-
-/*
- * Early reserved memory areas.
- */
-#define MAX_EARLY_RES 20
-
-struct early_res {
-       unsigned long start, end;
-       char name[16];
-};
-static struct early_res early_res[MAX_EARLY_RES] __initdata = {
-       { 0, PAGE_SIZE, "BIOS data page" },                     /* BIOS data page */
-#ifdef CONFIG_X86_TRAMPOLINE
-       { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" },
-#endif
-       {}
-};
-
-void __init reserve_early(unsigned long start, unsigned long end, char *name)
-{
-       int i;
-       struct early_res *r;
-       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
-               r = &early_res[i];
-               if (end > r->start && start < r->end)
-                       panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n",
-                             start, end - 1, name?name:"", r->start, r->end - 1, r->name);
-       }
-       if (i >= MAX_EARLY_RES)
-               panic("Too many early reservations");
-       r = &early_res[i];
-       r->start = start;
-       r->end = end;
-       if (name)
-               strncpy(r->name, name, sizeof(r->name) - 1);
-}
-
-void __init free_early(unsigned long start, unsigned long end)
-{
-       struct early_res *r;
-       int i, j;
-
-       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
-               r = &early_res[i];
-               if (start == r->start && end == r->end)
-                       break;
-       }
-       if (i >= MAX_EARLY_RES || !early_res[i].end)
-               panic("free_early on not reserved area: %lx-%lx!", start, end);
-
-       for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++)
-               ;
-
-       memmove(&early_res[i], &early_res[i + 1],
-              (j - 1 - i) * sizeof(struct early_res));
-
-       early_res[j - 1].end = 0;
-}
-
-void __init early_res_to_bootmem(unsigned long start, unsigned long end)
-{
-       int i;
-       unsigned long final_start, final_end;
-       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
-               struct early_res *r = &early_res[i];
-               final_start = max(start, r->start);
-               final_end = min(end, r->end);
-               if (final_start >= final_end)
-                       continue;
-               printk(KERN_INFO "  early res: %d [%lx-%lx] %s\n", i,
-                       final_start, final_end - 1, r->name);
-               reserve_bootmem_generic(final_start, final_end - final_start);
-       }
-}
-
-/* Check for already reserved areas */
-static inline int __init
-bad_addr(unsigned long *addrp, unsigned long size, unsigned long align)
-{
-       int i;
-       unsigned long addr = *addrp, last;
-       int changed = 0;
-again:
-       last = addr + size;
-       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
-               struct early_res *r = &early_res[i];
-               if (last >= r->start && addr < r->end) {
-                       *addrp = addr = round_up(r->end, align);
-                       changed = 1;
-                       goto again;
-               }
-       }
-       return changed;
-}
-
-/* Check for already reserved areas */
-static inline int __init
-bad_addr_size(unsigned long *addrp, unsigned long *sizep, unsigned long align)
-{
-       int i;
-       unsigned long addr = *addrp, last;
-       unsigned long size = *sizep;
-       int changed = 0;
-again:
-       last = addr + size;
-       for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
-               struct early_res *r = &early_res[i];
-               if (last > r->start && addr < r->start) {
-                       size = r->start - addr;
-                       changed = 1;
-                       goto again;
-               }
-               if (last > r->end && addr < r->end) {
-                       addr = round_up(r->end, align);
-                       size = last - addr;
-                       changed = 1;
-                       goto again;
-               }
-               if (last <= r->end && addr >= r->start) {
-                       (*sizep)++;
-                       return 0;
-               }
-       }
-       if (changed) {
-               *addrp = addr;
-               *sizep = size;
-       }
-       return changed;
-}
-/*
- * This function checks if any part of the range <start,end> is mapped
- * with type.
- */
-int
-e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-
-               if (type && ei->type != type)
-                       continue;
-               if (ei->addr >= end || ei->addr + ei->size <= start)
-                       continue;
-               return 1;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(e820_any_mapped);
-
-/*
- * This function checks if the entire range <start,end> is mapped with type.
- *
- * Note: this function only works correct if the e820 table is sorted and
- * not-overlapping, which is the case
- */
-int __init e820_all_mapped(unsigned long start, unsigned long end,
-                          unsigned type)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-
-               if (type && ei->type != type)
-                       continue;
-               /* is the region (part) in overlap with the current region ?*/
-               if (ei->addr >= end || ei->addr + ei->size <= start)
-                       continue;
-
-               /* if the region is at the beginning of <start,end> we move
-                * start to the end of the region since it's ok until there
-                */
-               if (ei->addr <= start)
-                       start = ei->addr + ei->size;
-               /*
-                * if start is now at or beyond end, we're done, full
-                * coverage
-                */
-               if (start >= end)
-                       return 1;
-       }
-       return 0;
-}
-
-/*
- * Find a free area with specified alignment in a specific range.
- */
-unsigned long __init find_e820_area(unsigned long start, unsigned long end,
-                                   unsigned long size, unsigned long align)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               unsigned long addr, last;
-               unsigned long ei_last;
-
-               if (ei->type != E820_RAM)
-                       continue;
-               addr = round_up(ei->addr, align);
-               ei_last = ei->addr + ei->size;
-               if (addr < start)
-                       addr = round_up(start, align);
-               if (addr >= ei_last)
-                       continue;
-               while (bad_addr(&addr, size, align) && addr+size <= ei_last)
-                       ;
-               last = addr + size;
-               if (last > ei_last)
-                       continue;
-               if (last > end)
-                       continue;
-               return addr;
-       }
-       return -1UL;
-}
-
-/*
- * Find next free range after *start
- */
-unsigned long __init find_e820_area_size(unsigned long start,
-                                        unsigned long *sizep,
-                                        unsigned long align)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               unsigned long addr, last;
-               unsigned long ei_last;
-
-               if (ei->type != E820_RAM)
-                       continue;
-               addr = round_up(ei->addr, align);
-               ei_last = ei->addr + ei->size;
-               if (addr < start)
-                       addr = round_up(start, align);
-               if (addr >= ei_last)
-                       continue;
-               *sizep = ei_last - addr;
-               while (bad_addr_size(&addr, sizep, align) &&
-                       addr + *sizep <= ei_last)
-                       ;
-               last = addr + *sizep;
-               if (last > ei_last)
-                       continue;
-               return addr;
-       }
-       return -1UL;
-
-}
-/*
- * Find the highest page frame number we have available
- */
-unsigned long __init e820_end_of_ram(void)
-{
-       unsigned long end_pfn;
-
-       end_pfn = find_max_pfn_with_active_regions();
-
-       if (end_pfn > max_pfn_mapped)
-               max_pfn_mapped = end_pfn;
-       if (max_pfn_mapped > MAXMEM>>PAGE_SHIFT)
-               max_pfn_mapped = MAXMEM>>PAGE_SHIFT;
-       if (end_pfn > end_user_pfn)
-               end_pfn = end_user_pfn;
-       if (end_pfn > max_pfn_mapped)
-               end_pfn = max_pfn_mapped;
-
-       printk(KERN_INFO "max_pfn_mapped = %lu\n", max_pfn_mapped);
-       return end_pfn;
-}
-
-/*
- * Mark e820 reserved areas as busy for the resource manager.
- */
-void __init e820_reserve_resources(void)
-{
-       int i;
-       struct resource *res;
-
-       res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
-       for (i = 0; i < e820.nr_map; i++) {
-               switch (e820.map[i].type) {
-               case E820_RAM:  res->name = "System RAM"; break;
-               case E820_ACPI: res->name = "ACPI Tables"; break;
-               case E820_NVS:  res->name = "ACPI Non-volatile Storage"; break;
-               default:        res->name = "reserved";
-               }
-               res->start = e820.map[i].addr;
-               res->end = res->start + e820.map[i].size - 1;
-               res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               insert_resource(&iomem_resource, res);
-               res++;
-       }
-}
-
-/*
- * Find the ranges of physical addresses that do not correspond to
- * e820 RAM areas and mark the corresponding pages as nosave for software
- * suspend and suspend to RAM.
- *
- * This function requires the e820 map to be sorted and without any
- * overlapping entries and assumes the first e820 area to be RAM.
- */
-void __init e820_mark_nosave_regions(void)
-{
-       int i;
-       unsigned long paddr;
-
-       paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
-       for (i = 1; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-
-               if (paddr < ei->addr)
-                       register_nosave_region(PFN_DOWN(paddr),
-                                               PFN_UP(ei->addr));
-
-               paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
-               if (ei->type != E820_RAM)
-                       register_nosave_region(PFN_UP(ei->addr),
-                                               PFN_DOWN(paddr));
-
-               if (paddr >= (end_pfn << PAGE_SHIFT))
-                       break;
-       }
-}
-
-/*
- * Finds an active region in the address range from start_pfn to end_pfn and
- * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
- */
-static int __init e820_find_active_region(const struct e820entry *ei,
-                                         unsigned long start_pfn,
-                                         unsigned long end_pfn,
-                                         unsigned long *ei_startpfn,
-                                         unsigned long *ei_endpfn)
-{
-       *ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
-       *ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) >> PAGE_SHIFT;
-
-       /* Skip map entries smaller than a page */
-       if (*ei_startpfn >= *ei_endpfn)
-               return 0;
-
-       /* Check if max_pfn_mapped should be updated */
-       if (ei->type != E820_RAM && *ei_endpfn > max_pfn_mapped)
-               max_pfn_mapped = *ei_endpfn;
-
-       /* Skip if map is outside the node */
-       if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
-                                   *ei_startpfn >= end_pfn)
-               return 0;
-
-       /* Check for overlaps */
-       if (*ei_startpfn < start_pfn)
-               *ei_startpfn = start_pfn;
-       if (*ei_endpfn > end_pfn)
-               *ei_endpfn = end_pfn;
-
-       /* Obey end_user_pfn to save on memmap */
-       if (*ei_startpfn >= end_user_pfn)
-               return 0;
-       if (*ei_endpfn > end_user_pfn)
-               *ei_endpfn = end_user_pfn;
-
-       return 1;
-}
-
-/* Walk the e820 map and register active regions within a node */
-void __init
-e820_register_active_regions(int nid, unsigned long start_pfn,
-                                                       unsigned long end_pfn)
-{
-       unsigned long ei_startpfn;
-       unsigned long ei_endpfn;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++)
-               if (e820_find_active_region(&e820.map[i],
-                                           start_pfn, end_pfn,
-                                           &ei_startpfn, &ei_endpfn))
-                       add_active_range(nid, ei_startpfn, ei_endpfn);
-}
-
-/*
- * Add a memory region to the kernel e820 map.
- */
-void __init add_memory_region(unsigned long start, unsigned long size, int type)
-{
-       int x = e820.nr_map;
-
-       if (x == E820MAX) {
-               printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
-               return;
-       }
-
-       e820.map[x].addr = start;
-       e820.map[x].size = size;
-       e820.map[x].type = type;
-       e820.nr_map++;
-}
-
-/*
- * Find the hole size (in bytes) in the memory range.
- * @start: starting address of the memory range to scan
- * @end: ending address of the memory range to scan
- */
-unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
-{
-       unsigned long start_pfn = start >> PAGE_SHIFT;
-       unsigned long end_pfn = end >> PAGE_SHIFT;
-       unsigned long ei_startpfn, ei_endpfn, ram = 0;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               if (e820_find_active_region(&e820.map[i],
-                                           start_pfn, end_pfn,
-                                           &ei_startpfn, &ei_endpfn))
-                       ram += ei_endpfn - ei_startpfn;
-       }
-       return end - start - (ram << PAGE_SHIFT);
-}
-
-static void __init e820_print_map(char *who)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               printk(KERN_INFO " %s: %016Lx - %016Lx ", who,
-                      (unsigned long long) e820.map[i].addr,
-                      (unsigned long long)
-                      (e820.map[i].addr + e820.map[i].size));
-               switch (e820.map[i].type) {
-               case E820_RAM:
-                       printk(KERN_CONT "(usable)\n");
-                       break;
-               case E820_RESERVED:
-                       printk(KERN_CONT "(reserved)\n");
-                       break;
-               case E820_ACPI:
-                       printk(KERN_CONT "(ACPI data)\n");
-                       break;
-               case E820_NVS:
-                       printk(KERN_CONT "(ACPI NVS)\n");
-                       break;
-               default:
-                       printk(KERN_CONT "type %u\n", e820.map[i].type);
-                       break;
-               }
-       }
-}
-
-/*
- * Sanitize the BIOS e820 map.
- *
- * Some e820 responses include overlapping entries. The following
- * replaces the original e820 map with a new one, removing overlaps.
- *
- */
-static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map)
-{
-       struct change_member {
-               struct e820entry *pbios; /* pointer to original bios entry */
-               unsigned long long addr; /* address for this change point */
-       };
-       static struct change_member change_point_list[2*E820MAX] __initdata;
-       static struct change_member *change_point[2*E820MAX] __initdata;
-       static struct e820entry *overlap_list[E820MAX] __initdata;
-       static struct e820entry new_bios[E820MAX] __initdata;
-       struct change_member *change_tmp;
-       unsigned long current_type, last_type;
-       unsigned long long last_addr;
-       int chgidx, still_changing;
-       int overlap_entries;
-       int new_bios_entry;
-       int old_nr, new_nr, chg_nr;
-       int i;
-
-       /*
-               Visually we're performing the following
-               (1,2,3,4 = memory types)...
-
-               Sample memory map (w/overlaps):
-                  ____22__________________
-                  ______________________4_
-                  ____1111________________
-                  _44_____________________
-                  11111111________________
-                  ____________________33__
-                  ___________44___________
-                  __________33333_________
-                  ______________22________
-                  ___________________2222_
-                  _________111111111______
-                  _____________________11_
-                  _________________4______
-
-               Sanitized equivalent (no overlap):
-                  1_______________________
-                  _44_____________________
-                  ___1____________________
-                  ____22__________________
-                  ______11________________
-                  _________1______________
-                  __________3_____________
-                  ___________44___________
-                  _____________33_________
-                  _______________2________
-                  ________________1_______
-                  _________________4______
-                  ___________________2____
-                  ____________________33__
-                  ______________________4_
-       */
-
-       /* if there's only one memory region, don't bother */
-       if (*pnr_map < 2)
-               return -1;
-
-       old_nr = *pnr_map;
-
-       /* bail out if we find any unreasonable addresses in bios map */
-       for (i = 0; i < old_nr; i++)
-               if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
-                       return -1;
-
-       /* create pointers for initial change-point information (for sorting) */
-       for (i = 0; i < 2 * old_nr; i++)
-               change_point[i] = &change_point_list[i];
-
-       /* record all known change-points (starting and ending addresses),
-          omitting those that are for empty memory regions */
-       chgidx = 0;
-       for (i = 0; i < old_nr; i++)    {
-               if (biosmap[i].size != 0) {
-                       change_point[chgidx]->addr = biosmap[i].addr;
-                       change_point[chgidx++]->pbios = &biosmap[i];
-                       change_point[chgidx]->addr = biosmap[i].addr +
-                               biosmap[i].size;
-                       change_point[chgidx++]->pbios = &biosmap[i];
-               }
-       }
-       chg_nr = chgidx;
-
-       /* sort change-point list by memory addresses (low -> high) */
-       still_changing = 1;
-       while (still_changing)  {
-               still_changing = 0;
-               for (i = 1; i < chg_nr; i++)  {
-                       unsigned long long curaddr, lastaddr;
-                       unsigned long long curpbaddr, lastpbaddr;
-
-                       curaddr = change_point[i]->addr;
-                       lastaddr = change_point[i - 1]->addr;
-                       curpbaddr = change_point[i]->pbios->addr;
-                       lastpbaddr = change_point[i - 1]->pbios->addr;
-
-                       /*
-                        * swap entries, when:
-                        *
-                        * curaddr > lastaddr or
-                        * curaddr == lastaddr and curaddr == curpbaddr and
-                        * lastaddr != lastpbaddr
-                        */
-                       if (curaddr < lastaddr ||
-                           (curaddr == lastaddr && curaddr == curpbaddr &&
-                            lastaddr != lastpbaddr)) {
-                               change_tmp = change_point[i];
-                               change_point[i] = change_point[i-1];
-                               change_point[i-1] = change_tmp;
-                               still_changing = 1;
-                       }
-               }
-       }
-
-       /* create a new bios memory map, removing overlaps */
-       overlap_entries = 0;     /* number of entries in the overlap table */
-       new_bios_entry = 0;      /* index for creating new bios map entries */
-       last_type = 0;           /* start with undefined memory type */
-       last_addr = 0;           /* start with 0 as last starting address */
-
-       /* loop through change-points, determining affect on the new bios map */
-       for (chgidx = 0; chgidx < chg_nr; chgidx++) {
-               /* keep track of all overlapping bios entries */
-               if (change_point[chgidx]->addr ==
-                   change_point[chgidx]->pbios->addr) {
-                       /*
-                        * add map entry to overlap list (> 1 entry
-                        * implies an overlap)
-                        */
-                       overlap_list[overlap_entries++] =
-                               change_point[chgidx]->pbios;
-               } else {
-                       /*
-                        * remove entry from list (order independent,
-                        * so swap with last)
-                        */
-                       for (i = 0; i < overlap_entries; i++) {
-                               if (overlap_list[i] ==
-                                   change_point[chgidx]->pbios)
-                                       overlap_list[i] =
-                                               overlap_list[overlap_entries-1];
-                       }
-                       overlap_entries--;
-               }
-               /*
-                * if there are overlapping entries, decide which
-                * "type" to use (larger value takes precedence --
-                * 1=usable, 2,3,4,4+=unusable)
-                */
-               current_type = 0;
-               for (i = 0; i < overlap_entries; i++)
-                       if (overlap_list[i]->type > current_type)
-                               current_type = overlap_list[i]->type;
-               /*
-                * continue building up new bios map based on this
-                * information
-                */
-               if (current_type != last_type)  {
-                       if (last_type != 0)      {
-                               new_bios[new_bios_entry].size =
-                                       change_point[chgidx]->addr - last_addr;
-                               /*
-                                * move forward only if the new size
-                                * was non-zero
-                                */
-                               if (new_bios[new_bios_entry].size != 0)
-                                       /*
-                                        * no more space left for new
-                                        * bios entries ?
-                                        */
-                                       if (++new_bios_entry >= E820MAX)
-                                               break;
-                       }
-                       if (current_type != 0)  {
-                               new_bios[new_bios_entry].addr =
-                                       change_point[chgidx]->addr;
-                               new_bios[new_bios_entry].type = current_type;
-                               last_addr = change_point[chgidx]->addr;
-                       }
-                       last_type = current_type;
-               }
-       }
-       /* retain count for new bios entries */
-       new_nr = new_bios_entry;
-
-       /* copy new bios mapping into original location */
-       memcpy(biosmap, new_bios, new_nr * sizeof(struct e820entry));
-       *pnr_map = new_nr;
-
-       return 0;
-}
-
-/*
- * Copy the BIOS e820 map into a safe place.
- *
- * Sanity-check it while we're at it..
- *
- * If we're lucky and live on a modern system, the setup code
- * will have given us a memory map that we can use to properly
- * set up memory.  If we aren't, we'll fake a memory map.
- */
-static int __init copy_e820_map(struct e820entry *biosmap, int nr_map)
-{
-       /* Only one memory region (or negative)? Ignore it */
-       if (nr_map < 2)
-               return -1;
-
-       do {
-               u64 start = biosmap->addr;
-               u64 size = biosmap->size;
-               u64 end = start + size;
-               u32 type = biosmap->type;
-
-               /* Overflow in 64 bits? Ignore the memory map. */
-               if (start > end)
-                       return -1;
-
-               add_memory_region(start, size, type);
-       } while (biosmap++, --nr_map);
-       return 0;
-}
-
-static void early_panic(char *msg)
-{
-       early_printk(msg);
-       panic(msg);
-}
-
-/* We're not void only for x86 32-bit compat */
-char * __init machine_specific_memory_setup(void)
-{
-       char *who = "BIOS-e820";
-       /*
-        * Try to copy the BIOS-supplied E820-map.
-        *
-        * Otherwise fake a memory map; one section from 0k->640k,
-        * the next section from 1mb->appropriate_mem_k
-        */
-       sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries);
-       if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0)
-               early_panic("Cannot find a valid memory map");
-       printk(KERN_INFO "BIOS-provided physical RAM map:\n");
-       e820_print_map(who);
-
-       /* In case someone cares... */
-       return who;
-}
-
-static int __init parse_memopt(char *p)
-{
-       if (!p)
-               return -EINVAL;
-       end_user_pfn = memparse(p, &p);
-       end_user_pfn >>= PAGE_SHIFT;
-       return 0;
-}
-early_param("mem", parse_memopt);
-
-static int userdef __initdata;
-
-static int __init parse_memmap_opt(char *p)
-{
-       char *oldp;
-       unsigned long long start_at, mem_size;
-
-       if (!strcmp(p, "exactmap")) {
-#ifdef CONFIG_CRASH_DUMP
-               /*
-                * If we are doing a crash dump, we still need to know
-                * the real mem size before original memory map is
-                * reset.
-                */
-               e820_register_active_regions(0, 0, -1UL);
-               saved_max_pfn = e820_end_of_ram();
-               remove_all_active_ranges();
-#endif
-               max_pfn_mapped = 0;
-               e820.nr_map = 0;
-               userdef = 1;
-               return 0;
-       }
-
-       oldp = p;
-       mem_size = memparse(p, &p);
-       if (p == oldp)
-               return -EINVAL;
-
-       userdef = 1;
-       if (*p == '@') {
-               start_at = memparse(p+1, &p);
-               add_memory_region(start_at, mem_size, E820_RAM);
-       } else if (*p == '#') {
-               start_at = memparse(p+1, &p);
-               add_memory_region(start_at, mem_size, E820_ACPI);
-       } else if (*p == '$') {
-               start_at = memparse(p+1, &p);
-               add_memory_region(start_at, mem_size, E820_RESERVED);
-       } else {
-               end_user_pfn = (mem_size >> PAGE_SHIFT);
-       }
-       return *p == '\0' ? 0 : -EINVAL;
-}
-early_param("memmap", parse_memmap_opt);
-
-void __init finish_e820_parsing(void)
-{
-       if (userdef) {
-               char nr = e820.nr_map;
-
-               if (sanitize_e820_map(e820.map, &nr) < 0)
-                       early_panic("Invalid user supplied memory map");
-               e820.nr_map = nr;
-
-               printk(KERN_INFO "user-defined physical RAM map:\n");
-               e820_print_map("user");
-       }
-}
-
-void __init update_memory_range(u64 start, u64 size, unsigned old_type,
-                               unsigned new_type)
-{
-       int i;
-
-       BUG_ON(old_type == new_type);
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               u64 final_start, final_end;
-               if (ei->type != old_type)
-                       continue;
-               /* totally covered? */
-               if (ei->addr >= start && ei->size <= size) {
-                       ei->type = new_type;
-                       continue;
-               }
-               /* partially covered */
-               final_start = max(start, ei->addr);
-               final_end = min(start + size, ei->addr + ei->size);
-               if (final_start >= final_end)
-                       continue;
-               add_memory_region(final_start, final_end - final_start,
-                                        new_type);
-       }
-}
-
-void __init update_e820(void)
-{
-       u8 nr_map;
-
-       nr_map = e820.nr_map;
-       if (sanitize_e820_map(e820.map, &nr_map))
-               return;
-       e820.nr_map = nr_map;
-       printk(KERN_INFO "modified physical RAM map:\n");
-       e820_print_map("modified");
-}
-
-unsigned long pci_mem_start = 0xaeedbabe;
-EXPORT_SYMBOL(pci_mem_start);
-
-/*
- * Search for the biggest gap in the low 32 bits of the e820
- * memory space.  We pass this space to PCI to assign MMIO resources
- * for hotplug or unconfigured devices in.
- * Hopefully the BIOS let enough space left.
- */
-__init void e820_setup_gap(void)
-{
-       unsigned long gapstart, gapsize, round;
-       unsigned long last;
-       int i;
-       int found = 0;
-
-       last = 0x100000000ull;
-       gapstart = 0x10000000;
-       gapsize = 0x400000;
-       i = e820.nr_map;
-       while (--i >= 0) {
-               unsigned long long start = e820.map[i].addr;
-               unsigned long long end = start + e820.map[i].size;
-
-               /*
-                * Since "last" is at most 4GB, we know we'll
-                * fit in 32 bits if this condition is true
-                */
-               if (last > end) {
-                       unsigned long gap = last - end;
-
-                       if (gap > gapsize) {
-                               gapsize = gap;
-                               gapstart = end;
-                               found = 1;
-                       }
-               }
-               if (start < last)
-                       last = start;
-       }
-
-       if (!found) {
-               gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
-               printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit "
-                      "address range\n"
-                      KERN_ERR "PCI: Unassigned devices with 32bit resource "
-                      "registers may break!\n");
-       }
-
-       /*
-        * See how much we want to round up: start off with
-        * rounding to the next 1MB area.
-        */
-       round = 0x100000;
-       while ((gapsize >> 4) > round)
-               round += round;
-       /* Fun with two's complement */
-       pci_mem_start = (gapstart + round) & -round;
-
-       printk(KERN_INFO
-              "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
-              pci_mem_start, gapstart, gapsize);
-}
-
-int __init arch_get_ram_range(int slot, u64 *addr, u64 *size)
-{
-       int i;
-
-       if (slot < 0 || slot >= e820.nr_map)
-               return -1;
-       for (i = slot; i < e820.nr_map; i++) {
-               if (e820.map[i].type != E820_RAM)
-                       continue;
-               break;
-       }
-       if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT))
-               return -1;
-       *addr = e820.map[i].addr;
-       *size = min_t(u64, e820.map[i].size + e820.map[i].addr,
-               max_pfn << PAGE_SHIFT) - *addr;
-       return i + 1;
-}
index 9f51e1ea9e8225e919ccb69ad6b4bc315c6f38cc..a4665f37cfc5dc9f3d3b7097c08166d061643de6 100644 (file)
@@ -50,7 +50,7 @@ static void __init fix_hypertransport_config(int num, int slot, int func)
 static void __init via_bugs(int  num, int slot, int func)
 {
 #ifdef CONFIG_GART_IOMMU
-       if ((end_pfn > MAX_DMA32_PFN ||  force_iommu) &&
+       if ((max_pfn > MAX_DMA32_PFN ||  force_iommu) &&
            !gart_iommu_aperture_allowed) {
                printk(KERN_INFO
                       "Looks like a VIA chipset. Disabling IOMMU."
@@ -98,17 +98,6 @@ static void __init nvidia_bugs(int num, int slot, int func)
 
 }
 
-static void __init ati_bugs(int num, int slot, int func)
-{
-#ifdef CONFIG_X86_IO_APIC
-       if (timer_over_8254 == 1) {
-               timer_over_8254 = 0;
-               printk(KERN_INFO
-               "ATI board detected. Disabling timer routing over 8254.\n");
-       }
-#endif
-}
-
 #define QFLAG_APPLY_ONCE       0x1
 #define QFLAG_APPLIED          0x2
 #define QFLAG_DONE             (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
@@ -126,8 +115,6 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs },
        { PCI_VENDOR_ID_VIA, PCI_ANY_ID,
          PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
-       { PCI_VENDOR_ID_ATI, PCI_ANY_ID,
-         PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, ati_bugs },
        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
          PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
        {}
index 77d424cf68b38e6b919f55b6fd895436e887fd74..06cc8d4254b180f622a33c879bca97f2c05b1643 100644 (file)
@@ -64,6 +64,17 @@ static int __init setup_noefi(char *arg)
 }
 early_param("noefi", setup_noefi);
 
+int add_efi_memmap;
+EXPORT_SYMBOL(add_efi_memmap);
+
+static int __init setup_add_efi_memmap(char *arg)
+{
+       add_efi_memmap = 1;
+       return 0;
+}
+early_param("add_efi_memmap", setup_add_efi_memmap);
+
+
 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
        return efi_call_virt2(get_time, tm, tc);
@@ -213,6 +224,50 @@ unsigned long efi_get_time(void)
                      eft.minute, eft.second);
 }
 
+/*
+ * Tell the kernel about the EFI memory map.  This might include
+ * more than the max 128 entries that can fit in the e820 legacy
+ * (zeropage) memory map.
+ */
+
+static void __init do_add_efi_memmap(void)
+{
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               efi_memory_desc_t *md = p;
+               unsigned long long start = md->phys_addr;
+               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+               int e820_type;
+
+               if (md->attribute & EFI_MEMORY_WB)
+                       e820_type = E820_RAM;
+               else
+                       e820_type = E820_RESERVED;
+               e820_add_region(start, size, e820_type);
+       }
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+}
+
+void __init efi_reserve_early(void)
+{
+       unsigned long pmap;
+
+#ifdef CONFIG_X86_32
+       pmap = boot_params.efi_info.efi_memmap;
+#else
+       pmap = (boot_params.efi_info.efi_memmap |
+               ((__u64)boot_params.efi_info.efi_memmap_hi<<32));
+#endif
+       memmap.phys_map = (void *)pmap;
+       memmap.nr_map = boot_params.efi_info.efi_memmap_size /
+               boot_params.efi_info.efi_memdesc_size;
+       memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
+       memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
+       reserve_early(pmap, pmap + memmap.nr_map * memmap.desc_size,
+                     "EFI memmap");
+}
+
 #if EFI_DEBUG
 static void __init print_efi_memmap(void)
 {
@@ -244,19 +299,11 @@ void __init efi_init(void)
 
 #ifdef CONFIG_X86_32
        efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
-       memmap.phys_map = (void *)boot_params.efi_info.efi_memmap;
 #else
        efi_phys.systab = (efi_system_table_t *)
                (boot_params.efi_info.efi_systab |
                 ((__u64)boot_params.efi_info.efi_systab_hi<<32));
-       memmap.phys_map = (void *)
-               (boot_params.efi_info.efi_memmap |
-                ((__u64)boot_params.efi_info.efi_memmap_hi<<32));
 #endif
-       memmap.nr_map = boot_params.efi_info.efi_memmap_size /
-               boot_params.efi_info.efi_memdesc_size;
-       memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
-       memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
 
        efi.systab = early_ioremap((unsigned long)efi_phys.systab,
                                   sizeof(efi_system_table_t));
@@ -370,6 +417,8 @@ void __init efi_init(void)
        if (memmap.desc_size != sizeof(efi_memory_desc_t))
                printk(KERN_WARNING "Kernel-defined memdesc"
                       "doesn't match the one from EFI!\n");
+       if (add_efi_memmap)
+               do_add_efi_memmap();
 
        /* Setup for EFI runtime service */
        reboot_type = BOOT_EFI;
@@ -424,7 +473,7 @@ void __init efi_enter_virtual_mode(void)
                size = md->num_pages << EFI_PAGE_SHIFT;
                end = md->phys_addr + size;
 
-               if (PFN_UP(end) <= max_pfn_mapped)
+               if (PFN_UP(end) <= max_low_pfn_mapped)
                        va = __va(md->phys_addr);
                else
                        va = efi_ioremap(md->phys_addr, size);
index d0060fdcccac1658968db527f4c05d791b056e6b..652c5287215fdb9500e4013794d559cfc4ace801 100644 (file)
@@ -97,13 +97,7 @@ void __init efi_call_phys_epilog(void)
        early_runtime_code_mapping_set_exec(0);
 }
 
-void __init efi_reserve_bootmem(void)
-{
-       reserve_bootmem_generic((unsigned long)memmap.phys_map,
-                               memmap.nr_map * memmap.desc_size);
-}
-
-void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
+void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size)
 {
        static unsigned pages_mapped __initdata;
        unsigned i, pages;
index c778e4fa55a2eacc79d34954c2fdcef1367d5732..cfe28a715434762352df73207da0fe422c76e713 100644 (file)
 #include <asm/percpu.h>
 #include <asm/dwarf2.h>
 #include <asm/processor-flags.h>
-#include "irq_vectors.h"
+#include <asm/irq_vectors.h>
 
 /*
  * We use macros for low-level operations which need to be overridden
  * for paravirtualization.  The following will never clobber any registers:
  *   INTERRUPT_RETURN (aka. "iret")
  *   GET_CR0_INTO_EAX (aka. "movl %cr0, %eax")
- *   ENABLE_INTERRUPTS_SYSCALL_RET (aka "sti; sysexit").
+ *   ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit").
  *
  * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must
  * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY).
@@ -349,7 +349,7 @@ sysenter_past_esp:
        xorl %ebp,%ebp
        TRACE_IRQS_ON
 1:     mov  PT_FS(%esp), %fs
-       ENABLE_INTERRUPTS_SYSCALL_RET
+       ENABLE_INTERRUPTS_SYSEXIT
        CFI_ENDPROC
 .pushsection .fixup,"ax"
 2:     movl $0,PT_FS(%esp)
@@ -874,10 +874,10 @@ ENTRY(native_iret)
 .previous
 END(native_iret)
 
-ENTRY(native_irq_enable_syscall_ret)
+ENTRY(native_irq_enable_sysexit)
        sti
        sysexit
-END(native_irq_enable_syscall_ret)
+END(native_irq_enable_sysexit)
 #endif
 
 KPROBE_ENTRY(int3)
@@ -1024,6 +1024,7 @@ ENTRY(xen_sysenter_target)
        RING0_INT_FRAME
        addl $5*4, %esp         /* remove xen-provided frame */
        jmp sysenter_past_esp
+       CFI_ENDPROC
 
 ENTRY(xen_hypervisor_callback)
        CFI_STARTPROC
index 556a8df522a7adcf9583164be4cad60e29b00a97..bb4e22f4892fd807cf4dfaee0a8ae41aefb9111b 100644 (file)
@@ -59,8 +59,7 @@
 #endif 
 
 #ifdef CONFIG_PARAVIRT
-ENTRY(native_irq_enable_syscall_ret)
-       movq    %gs:pda_oldrsp,%rsp
+ENTRY(native_usergs_sysret64)
        swapgs
        sysretq
 #endif /* CONFIG_PARAVIRT */
@@ -104,7 +103,7 @@ ENTRY(native_irq_enable_syscall_ret)
        .macro FAKE_STACK_FRAME child_rip
        /* push in order ss, rsp, eflags, cs, rip */
        xorl %eax, %eax
-       pushq %rax /* ss */
+       pushq $__KERNEL_DS /* ss */
        CFI_ADJUST_CFA_OFFSET   8
        /*CFI_REL_OFFSET        ss,0*/
        pushq %rax /* rsp */
@@ -169,13 +168,13 @@ ENTRY(ret_from_fork)
        CFI_ADJUST_CFA_OFFSET -4
        call schedule_tail
        GET_THREAD_INFO(%rcx)
-       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
+       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx)
        jnz rff_trace
 rff_action:    
        RESTORE_REST
        testl $3,CS-ARGOFFSET(%rsp)     # from kernel_thread?
        je   int_ret_from_sys_call
-       testl $_TIF_IA32,threadinfo_flags(%rcx)
+       testl $_TIF_IA32,TI_flags(%rcx)
        jnz  int_ret_from_sys_call
        RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
        jmp ret_from_sys_call
@@ -244,7 +243,8 @@ ENTRY(system_call_after_swapgs)
        movq  %rcx,RIP-ARGOFFSET(%rsp)
        CFI_REL_OFFSET rip,RIP-ARGOFFSET
        GET_THREAD_INFO(%rcx)
-       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx)
+       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP), \
+               TI_flags(%rcx)
        jnz tracesys
        cmpq $__NR_syscall_max,%rax
        ja badsys
@@ -263,7 +263,7 @@ sysret_check:
        GET_THREAD_INFO(%rcx)
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
-       movl threadinfo_flags(%rcx),%edx
+       movl TI_flags(%rcx),%edx
        andl %edi,%edx
        jnz  sysret_careful 
        CFI_REMEMBER_STATE
@@ -275,7 +275,8 @@ sysret_check:
        CFI_REGISTER    rip,rcx
        RESTORE_ARGS 0,-ARG_SKIP,1
        /*CFI_REGISTER  rflags,r11*/
-       ENABLE_INTERRUPTS_SYSCALL_RET
+       movq    %gs:pda_oldrsp, %rsp
+       USERGS_SYSRET64
 
        CFI_RESTORE_STATE
        /* Handle reschedules */
@@ -305,7 +306,7 @@ sysret_signal:
        leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
        xorl %esi,%esi # oldset -> arg2
        call ptregscall_common
-1:     movl $_TIF_NEED_RESCHED,%edi
+1:     movl $_TIF_WORK_MASK,%edi
        /* Use IRET because user could have changed frame. This
           works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
        DISABLE_INTERRUPTS(CLBR_NONE)
@@ -347,10 +348,10 @@ int_ret_from_sys_call:
 int_with_check:
        LOCKDEP_SYS_EXIT_IRQ
        GET_THREAD_INFO(%rcx)
-       movl threadinfo_flags(%rcx),%edx
+       movl TI_flags(%rcx),%edx
        andl %edi,%edx
        jnz   int_careful
-       andl    $~TS_COMPAT,threadinfo_status(%rcx)
+       andl    $~TS_COMPAT,TI_status(%rcx)
        jmp   retint_swapgs
 
        /* Either reschedule or signal or syscall exit tracking needed. */
@@ -393,7 +394,7 @@ int_signal:
        movq %rsp,%rdi          # &ptregs -> arg1
        xorl %esi,%esi          # oldset -> arg2
        call do_notify_resume
-1:     movl $_TIF_NEED_RESCHED,%edi    
+1:     movl $_TIF_WORK_MASK,%edi
 int_restore_rest:
        RESTORE_REST
        DISABLE_INTERRUPTS(CLBR_NONE)
@@ -420,7 +421,6 @@ END(\label)
        PTREGSCALL stub_clone, sys_clone, %r8
        PTREGSCALL stub_fork, sys_fork, %rdi
        PTREGSCALL stub_vfork, sys_vfork, %rdi
-       PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
        PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
        PTREGSCALL stub_iopl, sys_iopl, %rsi
 
@@ -559,7 +559,7 @@ retint_with_reschedule:
        movl $_TIF_WORK_MASK,%edi
 retint_check:
        LOCKDEP_SYS_EXIT_IRQ
-       movl threadinfo_flags(%rcx),%edx
+       movl TI_flags(%rcx),%edx
        andl %edi,%edx
        CFI_REMEMBER_STATE
        jnz  retint_careful
@@ -647,17 +647,16 @@ retint_signal:
        RESTORE_REST
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
-       movl $_TIF_NEED_RESCHED,%edi
        GET_THREAD_INFO(%rcx)
-       jmp retint_check
+       jmp retint_with_reschedule
 
 #ifdef CONFIG_PREEMPT
        /* Returning to kernel space. Check if we need preemption */
        /* rcx:  threadinfo. interrupts off. */
 ENTRY(retint_kernel)
-       cmpl $0,threadinfo_preempt_count(%rcx)
+       cmpl $0,TI_preempt_count(%rcx)
        jnz  retint_restore_args
-       bt  $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
+       bt  $TIF_NEED_RESCHED,TI_flags(%rcx)
        jnc  retint_restore_args
        bt   $9,EFLAGS-ARGOFFSET(%rsp)  /* interrupts off? */
        jnc  retint_restore_args
@@ -720,6 +719,10 @@ ENTRY(apic_timer_interrupt)
        apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
 END(apic_timer_interrupt)
 
+ENTRY(uv_bau_message_intr1)
+       apicinterrupt 220,uv_bau_message_interrupt
+END(uv_bau_message_intr1)
+
 ENTRY(error_interrupt)
        apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
 END(error_interrupt)
@@ -733,6 +736,7 @@ END(spurious_interrupt)
  */            
        .macro zeroentry sym
        INTR_FRAME
+       PARAVIRT_ADJUST_EXCEPTION_FRAME
        pushq $0        /* push error code/oldrax */ 
        CFI_ADJUST_CFA_OFFSET 8
        pushq %rax      /* push real oldrax to the rdi slot */ 
@@ -745,6 +749,7 @@ END(spurious_interrupt)
 
        .macro errorentry sym
        XCPT_FRAME
+       PARAVIRT_ADJUST_EXCEPTION_FRAME
        pushq %rax
        CFI_ADJUST_CFA_OFFSET 8
        CFI_REL_OFFSET rax,0
@@ -814,7 +819,7 @@ paranoid_restore\trace:
        jmp irq_return
 paranoid_userspace\trace:
        GET_THREAD_INFO(%rcx)
-       movl threadinfo_flags(%rcx),%ebx
+       movl TI_flags(%rcx),%ebx
        andl $_TIF_WORK_MASK,%ebx
        jz paranoid_swapgs\trace
        movq %rsp,%rdi                  /* &pt_regs */
@@ -912,7 +917,7 @@ error_exit:
        testl %eax,%eax
        jne  retint_kernel
        LOCKDEP_SYS_EXIT_IRQ
-       movl  threadinfo_flags(%rcx),%edx
+       movl  TI_flags(%rcx),%edx
        movl  $_TIF_WORK_MASK,%edi
        andl  %edi,%edx
        jnz  retint_careful
@@ -926,11 +931,11 @@ error_kernelspace:
           iret run with kernel gs again, so don't set the user space flag.
           B stepping K8s sometimes report an truncated RIP for IRET 
           exceptions returning to compat mode. Check for these here too. */
-       leaq irq_return(%rip),%rbp
-       cmpq %rbp,RIP(%rsp) 
+       leaq irq_return(%rip),%rcx
+       cmpq %rcx,RIP(%rsp)
        je   error_swapgs
-       movl %ebp,%ebp  /* zero extend */
-       cmpq %rbp,RIP(%rsp) 
+       movl %ecx,%ecx  /* zero extend */
+       cmpq %rcx,RIP(%rsp)
        je   error_swapgs
        cmpq $gs_change,RIP(%rsp)
         je   error_swapgs
@@ -939,7 +944,7 @@ KPROBE_END(error_entry)
        
        /* Reload gs selector with exception handling */
        /* edi:  new selector */ 
-ENTRY(load_gs_index)
+ENTRY(native_load_gs_index)
        CFI_STARTPROC
        pushf
        CFI_ADJUST_CFA_OFFSET 8
@@ -953,7 +958,7 @@ gs_change:
        CFI_ADJUST_CFA_OFFSET -8
         ret
        CFI_ENDPROC
-ENDPROC(load_gs_index)
+ENDPROC(native_load_gs_index)
        
         .section __ex_table,"a"
         .align 8
@@ -1120,10 +1125,6 @@ ENTRY(coprocessor_segment_overrun)
        zeroentry do_coprocessor_segment_overrun
 END(coprocessor_segment_overrun)
 
-ENTRY(reserved)
-       zeroentry do_reserved
-END(reserved)
-
        /* runs on exception stack */
 ENTRY(double_fault)
        XCPT_FRAME
index cbaaf69bedb29c92055e2272a12efba7f49f9ee1..1fa8be5bd217b5c45a649e6745b847567a9553f6 100644 (file)
@@ -51,7 +51,7 @@ void __init setup_apic_routing(void)
        else
 #endif
 
-       if (num_possible_cpus() <= 8)
+       if (max_physical_apicid < 8)
                genapic = &apic_flat;
        else
                genapic = &apic_physflat;
index ebf13908a743b6cd8cbdc231d0758f2388b92243..711f11c30b060dd17bc86be21b439d2068040489 100644 (file)
@@ -5,9 +5,10 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
+#include <linux/kernel.h>
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
@@ -20,6 +21,7 @@
 #include <asm/smp.h>
 #include <asm/ipi.h>
 #include <asm/genapic.h>
+#include <asm/pgtable.h>
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
 
@@ -55,37 +57,37 @@ static cpumask_t uv_vector_allocation_domain(int cpu)
 int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip)
 {
        unsigned long val;
-       int nasid;
+       int pnode;
 
-       nasid = uv_apicid_to_nasid(phys_apicid);
+       pnode = uv_apicid_to_pnode(phys_apicid);
        val = (1UL << UVH_IPI_INT_SEND_SHFT) |
            (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
            (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
            APIC_DM_INIT;
-       uv_write_global_mmr64(nasid, UVH_IPI_INT, val);
+       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
        mdelay(10);
 
        val = (1UL << UVH_IPI_INT_SEND_SHFT) |
            (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
            (((long)start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
            APIC_DM_STARTUP;
-       uv_write_global_mmr64(nasid, UVH_IPI_INT, val);
+       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
        return 0;
 }
 
 static void uv_send_IPI_one(int cpu, int vector)
 {
        unsigned long val, apicid, lapicid;
-       int nasid;
+       int pnode;
 
        apicid = per_cpu(x86_cpu_to_apicid, cpu); /* ZZZ - cache node-local ? */
        lapicid = apicid & 0x3f;                /* ZZZ macro needed */
-       nasid = uv_apicid_to_nasid(apicid);
+       pnode = uv_apicid_to_pnode(apicid);
        val =
            (1UL << UVH_IPI_INT_SEND_SHFT) | (lapicid <<
                                              UVH_IPI_INT_APIC_ID_SHFT) |
            (vector << UVH_IPI_INT_VECTOR_SHFT);
-       uv_write_global_mmr64(nasid, UVH_IPI_INT, val);
+       uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
 }
 
 static void uv_send_IPI_mask(cpumask_t mask, int vector)
@@ -159,39 +161,146 @@ struct genapic apic_x2apic_uv_x = {
        .phys_pkg_id = phys_pkg_id,     /* Fixme ZZZ */
 };
 
-static __cpuinit void set_x2apic_extra_bits(int nasid)
+static __cpuinit void set_x2apic_extra_bits(int pnode)
 {
-       __get_cpu_var(x2apic_extra_bits) = ((nasid >> 1) << 6);
+       __get_cpu_var(x2apic_extra_bits) = (pnode << 6);
 }
 
 /*
  * Called on boot cpu.
  */
+static __init int boot_pnode_to_blade(int pnode)
+{
+       int blade;
+
+       for (blade = 0; blade < uv_num_possible_blades(); blade++)
+               if (pnode == uv_blade_info[blade].pnode)
+                       return blade;
+       BUG();
+}
+
+struct redir_addr {
+       unsigned long redirect;
+       unsigned long alias;
+};
+
+#define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT
+
+static __initdata struct redir_addr redir_addrs[] = {
+       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_SI_ALIAS0_OVERLAY_CONFIG},
+       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_SI_ALIAS1_OVERLAY_CONFIG},
+       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_SI_ALIAS2_OVERLAY_CONFIG},
+};
+
+static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
+{
+       union uvh_si_alias0_overlay_config_u alias;
+       union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(redir_addrs); i++) {
+               alias.v = uv_read_local_mmr(redir_addrs[i].alias);
+               if (alias.s.base == 0) {
+                       *size = (1UL << alias.s.m_alias);
+                       redirect.v = uv_read_local_mmr(redir_addrs[i].redirect);
+                       *base = (unsigned long)redirect.s.dest_base << DEST_SHIFT;
+                       return;
+               }
+       }
+       BUG();
+}
+
+static __init void map_low_mmrs(void)
+{
+       init_extra_mapping_uc(UV_GLOBAL_MMR32_BASE, UV_GLOBAL_MMR32_SIZE);
+       init_extra_mapping_uc(UV_LOCAL_MMR_BASE, UV_LOCAL_MMR_SIZE);
+}
+
+enum map_type {map_wb, map_uc};
+
+static void map_high(char *id, unsigned long base, int shift, enum map_type map_type)
+{
+       unsigned long bytes, paddr;
+
+       paddr = base << shift;
+       bytes = (1UL << shift);
+       printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
+                                               paddr + bytes);
+       if (map_type == map_uc)
+               init_extra_mapping_uc(paddr, bytes);
+       else
+               init_extra_mapping_wb(paddr, bytes);
+
+}
+static __init void map_gru_high(int max_pnode)
+{
+       union uvh_rh_gam_gru_overlay_config_mmr_u gru;
+       int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
+
+       gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
+       if (gru.s.enable)
+               map_high("GRU", gru.s.base, shift, map_wb);
+}
+
+static __init void map_config_high(int max_pnode)
+{
+       union uvh_rh_gam_cfg_overlay_config_mmr_u cfg;
+       int shift = UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_BASE_SHFT;
+
+       cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR);
+       if (cfg.s.enable)
+               map_high("CONFIG", cfg.s.base, shift, map_uc);
+}
+
+static __init void map_mmr_high(int max_pnode)
+{
+       union uvh_rh_gam_mmr_overlay_config_mmr_u mmr;
+       int shift = UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT;
+
+       mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
+       if (mmr.s.enable)
+               map_high("MMR", mmr.s.base, shift, map_uc);
+}
+
+static __init void map_mmioh_high(int max_pnode)
+{
+       union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
+       int shift = UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
+
+       mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
+       if (mmioh.s.enable)
+               map_high("MMIOH", mmioh.s.base, shift, map_uc);
+}
+
 static __init void uv_system_init(void)
 {
        union uvh_si_addr_map_config_u m_n_config;
-       int bytes, nid, cpu, lcpu, nasid, last_nasid, blade;
-       unsigned long mmr_base;
+       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;
+       unsigned long mmr_base, present;
+
+       map_low_mmrs();
 
        m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
+       m_val = m_n_config.s.m_skt;
+       n_val = m_n_config.s.n_skt;
        mmr_base =
            uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
            ~UV_MMR_ENABLE;
        printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base);
 
-       last_nasid = -1;
-       for_each_possible_cpu(cpu) {
-               nid = cpu_to_node(cpu);
-               nasid = uv_apicid_to_nasid(per_cpu(x86_cpu_to_apicid, cpu));
-               if (nasid != last_nasid)
-                       uv_possible_blades++;
-               last_nasid = nasid;
-       }
+       for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
+               uv_possible_blades +=
+                 hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8));
        printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades());
 
        bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades();
        uv_blade_info = alloc_bootmem_pages(bytes);
 
+       get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size);
+
        bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes();
        uv_node_to_blade = alloc_bootmem_pages(bytes);
        memset(uv_node_to_blade, 255, bytes);
@@ -200,43 +309,62 @@ static __init void uv_system_init(void)
        uv_cpu_to_blade = alloc_bootmem_pages(bytes);
        memset(uv_cpu_to_blade, 255, bytes);
 
-       last_nasid = -1;
-       blade = -1;
-       lcpu = -1;
-       for_each_possible_cpu(cpu) {
-               nid = cpu_to_node(cpu);
-               nasid = uv_apicid_to_nasid(per_cpu(x86_cpu_to_apicid, cpu));
-               if (nasid != last_nasid) {
-                       blade++;
-                       lcpu = -1;
-                       uv_blade_info[blade].nr_posible_cpus = 0;
+       blade = 0;
+       for (i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) {
+               present = uv_read_local_mmr(UVH_NODE_PRESENT_TABLE + i * 8);
+               for (j = 0; j < 64; j++) {
+                       if (!test_bit(j, &present))
+                               continue;
+                       uv_blade_info[blade].pnode = (i * 64 + j);
+                       uv_blade_info[blade].nr_possible_cpus = 0;
                        uv_blade_info[blade].nr_online_cpus = 0;
+                       blade++;
                }
-               last_nasid = nasid;
-               lcpu++;
+       }
 
-               uv_cpu_hub_info(cpu)->m_val = m_n_config.s.m_skt;
-               uv_cpu_hub_info(cpu)->n_val = m_n_config.s.n_skt;
+       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;
+
+       for_each_present_cpu(cpu) {
+               nid = cpu_to_node(cpu);
+               pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu));
+               blade = boot_pnode_to_blade(pnode);
+               lcpu = uv_blade_info[blade].nr_possible_cpus;
+               uv_blade_info[blade].nr_possible_cpus++;
+
+               uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base;
+               uv_cpu_hub_info(cpu)->lowmem_remap_top =
+                                       lowmem_redir_base + lowmem_redir_size;
+               uv_cpu_hub_info(cpu)->m_val = m_val;
+               uv_cpu_hub_info(cpu)->n_val = m_val;
                uv_cpu_hub_info(cpu)->numa_blade_id = blade;
                uv_cpu_hub_info(cpu)->blade_processor_id = lcpu;
-               uv_cpu_hub_info(cpu)->local_nasid = nasid;
-               uv_cpu_hub_info(cpu)->gnode_upper =
-                   nasid & ~((1 << uv_hub_info->n_val) - 1);
+               uv_cpu_hub_info(cpu)->pnode = pnode;
+               uv_cpu_hub_info(cpu)->pnode_mask = (1 << n_val) - 1;
+               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)->global_mmr_base = mmr_base;
                uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */
-               uv_blade_info[blade].nasid = nasid;
-               uv_blade_info[blade].nr_posible_cpus++;
                uv_node_to_blade[nid] = blade;
                uv_cpu_to_blade[cpu] = blade;
+               max_pnode = max(pnode, max_pnode);
 
-               printk(KERN_DEBUG "UV cpu %d, apicid 0x%x, nasid %d, nid %d\n",
-                      cpu, per_cpu(x86_cpu_to_apicid, cpu), nasid, nid);
-               printk(KERN_DEBUG "UV   lcpu %d, blade %d\n", lcpu, blade);
+               printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, "
+                       "lcpu %d, blade %d\n",
+                       cpu, per_cpu(x86_cpu_to_apicid, cpu), pnode, nid,
+                       lcpu, blade);
        }
+
+       map_gru_high(max_pnode);
+       map_mmr_high(max_pnode);
+       map_config_high(max_pnode);
+       map_mmioh_high(max_pnode);
 }
 
 /*
  * Called on each cpu to initialize the per_cpu UV data area.
+ *     ZZZ hotplug not supported yet
  */
 void __cpuinit uv_cpu_init(void)
 {
@@ -246,5 +374,5 @@ void __cpuinit uv_cpu_init(void)
        uv_blade_info[uv_numa_blade_id()].nr_online_cpus++;
 
        if (get_uv_system_type() == UV_NON_UNIQUE_APIC)
-               set_x2apic_extra_bits(uv_hub_info->local_nasid);
+               set_x2apic_extra_bits(uv_hub_info->pnode);
 }
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
new file mode 100644 (file)
index 0000000..3e66bd3
--- /dev/null
@@ -0,0 +1,55 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/bios_ebda.h>
+
+#define BIOS_LOWMEM_KILOBYTES 0x413
+
+/*
+ * The BIOS places the EBDA/XBDA at the top of conventional
+ * memory, and usually decreases the reported amount of
+ * conventional memory (int 0x12) too. This also contains a
+ * workaround for Dell systems that neglect to reserve EBDA.
+ * The same workaround also avoids a problem with the AMD768MPX
+ * chipset: reserve a page before VGA to prevent PCI prefetch
+ * into it (errata #56). Usually the page is reserved anyways,
+ * unless you have no PS/2 mouse plugged in.
+ */
+void __init reserve_ebda_region(void)
+{
+       unsigned int lowmem, ebda_addr;
+
+       /* To determine the position of the EBDA and the */
+       /* end of conventional memory, we need to look at */
+       /* the BIOS data area. In a paravirtual environment */
+       /* that area is absent. We'll just have to assume */
+       /* that the paravirt case can handle memory setup */
+       /* correctly, without our help. */
+       if (paravirt_enabled())
+               return;
+
+       /* end of low (conventional) memory */
+       lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES);
+       lowmem <<= 10;
+
+       /* start of EBDA area */
+       ebda_addr = get_bios_ebda();
+
+       /* Fixup: bios puts an EBDA in the top 64K segment */
+       /* of conventional memory, but does not adjust lowmem. */
+       if ((lowmem - ebda_addr) <= 0x10000)
+               lowmem = ebda_addr;
+
+       /* Fixup: bios does not report an EBDA at all. */
+       /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */
+       if ((ebda_addr == 0) && (lowmem >= 0x9f000))
+               lowmem = 0x9f000;
+
+       /* Paranoia: should never happen, but... */
+       if ((lowmem == 0) || (lowmem >= 0x100000))
+               lowmem = 0x9f000;
+
+       /* reserve all memory between lowmem and the 1MB mark */
+       reserve_early_overlap_ok(lowmem, 0x100000, "BIOS reserved");
+}
index 3db0590589276e5ecbc1d74dd1331264bc414f11..fa1d25dd83e3fa18cc2a445841c61e1e1b8b571c 100644 (file)
@@ -8,7 +8,34 @@
 #include <linux/init.h>
 #include <linux/start_kernel.h>
 
+#include <asm/setup.h>
+#include <asm/sections.h>
+#include <asm/e820.h>
+#include <asm/bios_ebda.h>
+
 void __init i386_start_kernel(void)
 {
+       reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* Reserve INITRD */
+       if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
+               u64 ramdisk_image = boot_params.hdr.ramdisk_image;
+               u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
+               u64 ramdisk_end   = ramdisk_image + ramdisk_size;
+               reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
+       }
+#endif
+       reserve_early(init_pg_tables_start, init_pg_tables_end,
+                       "INIT_PG_TABLE");
+
+       reserve_ebda_region();
+
+       /*
+        * At this point everything still needed from the boot loader
+        * or BIOS or kernel text should be early reserved or marked not
+        * RAM in e820. All other memory is free game.
+        */
+
        start_kernel();
 }
index e25c57b8aa844937742f246288e9ffa2e2be5229..c9781982914693cbb6ba98bf7cea94b1a291c8a5 100644 (file)
 #include <asm/e820.h>
 #include <asm/bios_ebda.h>
 
+/* boot cpu pda */
+static struct x8664_pda _boot_cpu_pda __read_mostly;
+
+#ifdef CONFIG_SMP
+/*
+ * We install an empty cpu_pda pointer table to indicate to early users
+ * (numa_set_node) that the cpu_pda pointer table for cpus other than
+ * the boot cpu is not yet setup.
+ */
+static struct x8664_pda *__cpu_pda[NR_CPUS] __initdata;
+#else
+static struct x8664_pda *__cpu_pda[NR_CPUS] __read_mostly;
+#endif
+
 static void __init zap_identity_mappings(void)
 {
        pgd_t *pgd = pgd_offset_k(0UL);
@@ -51,74 +65,6 @@ static void __init copy_bootdata(char *real_mode_data)
        }
 }
 
-#define BIOS_LOWMEM_KILOBYTES 0x413
-
-/*
- * The BIOS places the EBDA/XBDA at the top of conventional
- * memory, and usually decreases the reported amount of
- * conventional memory (int 0x12) too. This also contains a
- * workaround for Dell systems that neglect to reserve EBDA.
- * The same workaround also avoids a problem with the AMD768MPX
- * chipset: reserve a page before VGA to prevent PCI prefetch
- * into it (errata #56). Usually the page is reserved anyways,
- * unless you have no PS/2 mouse plugged in.
- */
-static void __init reserve_ebda_region(void)
-{
-       unsigned int lowmem, ebda_addr;
-
-       /* To determine the position of the EBDA and the */
-       /* end of conventional memory, we need to look at */
-       /* the BIOS data area. In a paravirtual environment */
-       /* that area is absent. We'll just have to assume */
-       /* that the paravirt case can handle memory setup */
-       /* correctly, without our help. */
-       if (paravirt_enabled())
-               return;
-
-       /* end of low (conventional) memory */
-       lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES);
-       lowmem <<= 10;
-
-       /* start of EBDA area */
-       ebda_addr = get_bios_ebda();
-
-       /* Fixup: bios puts an EBDA in the top 64K segment */
-       /* of conventional memory, but does not adjust lowmem. */
-       if ((lowmem - ebda_addr) <= 0x10000)
-               lowmem = ebda_addr;
-
-       /* Fixup: bios does not report an EBDA at all. */
-       /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */
-       if ((ebda_addr == 0) && (lowmem >= 0x9f000))
-               lowmem = 0x9f000;
-
-       /* Paranoia: should never happen, but... */
-       if ((lowmem == 0) || (lowmem >= 0x100000))
-               lowmem = 0x9f000;
-
-       /* reserve all memory between lowmem and the 1MB mark */
-       reserve_early(lowmem, 0x100000, "BIOS reserved");
-}
-
-static void __init reserve_setup_data(void)
-{
-       struct setup_data *data;
-       unsigned long pa_data;
-       char buf[32];
-
-       if (boot_params.hdr.version < 0x0209)
-               return;
-       pa_data = boot_params.hdr.setup_data;
-       while (pa_data) {
-               data = early_ioremap(pa_data, sizeof(*data));
-               sprintf(buf, "setup data %x", data->type);
-               reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
-               pa_data = data->next;
-               early_iounmap(data, sizeof(*data));
-       }
-}
-
 void __init x86_64_start_kernel(char * real_mode_data)
 {
        int i;
@@ -156,10 +102,17 @@ void __init x86_64_start_kernel(char * real_mode_data)
 
        early_printk("Kernel alive\n");
 
-       for (i = 0; i < NR_CPUS; i++)
-               cpu_pda(i) = &boot_cpu_pda[i];
-
+       _cpu_pda = __cpu_pda;
+       cpu_pda(0) = &_boot_cpu_pda;
        pda_init(0);
+
+       early_printk("Kernel really alive\n");
+
+       x86_64_start_reservations(real_mode_data);
+}
+
+void __init x86_64_start_reservations(char *real_mode_data)
+{
        copy_bootdata(__va(real_mode_data));
 
        reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
@@ -175,7 +128,6 @@ void __init x86_64_start_kernel(char * real_mode_data)
 #endif
 
        reserve_ebda_region();
-       reserve_setup_data();
 
        /*
         * At this point everything still needed from the boot loader
index f7357cc0162c2f1c4786b3208e8524b51837fef8..f67e93441caf2a892d637a54061257b1d4002828 100644 (file)
@@ -194,6 +194,7 @@ default_entry:
        xorl %ebx,%ebx                          /* %ebx is kept at zero */
 
        movl $pa(pg0), %edi
+       movl %edi, pa(init_pg_tables_start)
        movl $pa(swapper_pg_pmd), %edx
        movl $PTE_ATTR, %eax
 10:
@@ -219,6 +220,8 @@ default_entry:
        jb 10b
 1:
        movl %edi,pa(init_pg_tables_end)
+       shrl $12, %eax
+       movl %eax, pa(max_pfn_mapped)
 
        /* Do early initialization of the fixmap area */
        movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax
@@ -228,6 +231,7 @@ default_entry:
 page_pde_offset = (__PAGE_OFFSET >> 20);
 
        movl $pa(pg0), %edi
+       movl %edi, pa(init_pg_tables_start)
        movl $pa(swapper_pg_dir), %edx
        movl $PTE_ATTR, %eax
 10:
@@ -249,6 +253,8 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
        cmpl %ebp,%eax
        jb 10b
        movl %edi,pa(init_pg_tables_end)
+       shrl $12, %eax
+       movl %eax, pa(max_pfn_mapped)
 
        /* Do early initialization of the fixmap area */
        movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax
@@ -446,10 +452,13 @@ is386:    movl $2,%ecx            # set MP
        je   1f
        movl $(__KERNEL_PERCPU), %eax
        movl %eax,%fs           # set this cpu's percpu
-       jmp initialize_secondary # all other CPUs call initialize_secondary
+       movl (stack_start), %esp
 1:
 #endif /* CONFIG_SMP */
-       jmp i386_start_kernel
+       jmp *(initial_code)
+.align 4
+ENTRY(initial_code)
+       .long i386_start_kernel
 
 /*
  * We depend on ET to be correct. This checks for 287/387.
index b817974ef9420bba5702327a1089156dcb5d72c3..b07ac7b217cb161e2b4f35b1edf4677fe32f0d64 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/page.h>
 #include <asm/msr.h>
 #include <asm/cache.h>
+#include <asm/processor-flags.h>
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/asm-offsets.h>
  *
  */
 
+#define pud_index(x)   (((x) >> PUD_SHIFT) & (PTRS_PER_PUD-1))
+
+L4_PAGE_OFFSET = pgd_index(__PAGE_OFFSET)
+L3_PAGE_OFFSET = pud_index(__PAGE_OFFSET)
+L4_START_KERNEL = pgd_index(__START_KERNEL_map)
+L3_START_KERNEL = pud_index(__START_KERNEL_map)
+
        .text
        .section .text.head
        .code64
@@ -76,8 +84,8 @@ startup_64:
        /* Fixup the physical addresses in the page table
         */
        addq    %rbp, init_level4_pgt + 0(%rip)
-       addq    %rbp, init_level4_pgt + (258*8)(%rip)
-       addq    %rbp, init_level4_pgt + (511*8)(%rip)
+       addq    %rbp, init_level4_pgt + (L4_PAGE_OFFSET*8)(%rip)
+       addq    %rbp, init_level4_pgt + (L4_START_KERNEL*8)(%rip)
 
        addq    %rbp, level3_ident_pgt + 0(%rip)
 
@@ -154,9 +162,7 @@ ENTRY(secondary_startup_64)
         */
 
        /* Enable PAE mode and PGE */
-       xorq    %rax, %rax
-       btsq    $5, %rax
-       btsq    $7, %rax
+       movl    $(X86_CR4_PAE | X86_CR4_PGE), %eax
        movq    %rax, %cr4
 
        /* Setup early boot stage 4 level pagetables. */
@@ -184,19 +190,15 @@ ENTRY(secondary_startup_64)
 1:     wrmsr                           /* Make changes effective */
 
        /* Setup cr0 */
-#define CR0_PM                         1               /* protected mode */
-#define CR0_MP                         (1<<1)
-#define CR0_ET                         (1<<4)
-#define CR0_NE                         (1<<5)
-#define CR0_WP                         (1<<16)
-#define CR0_AM                         (1<<18)
-#define CR0_PAGING                     (1<<31)
-       movl $CR0_PM|CR0_MP|CR0_ET|CR0_NE|CR0_WP|CR0_AM|CR0_PAGING,%eax
+#define CR0_STATE      (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
+                        X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
+                        X86_CR0_PG)
+       movl    $CR0_STATE, %eax
        /* Make changes effective */
        movq    %rax, %cr0
 
        /* Setup a boot time stack */
-       movq init_rsp(%rip),%rsp
+       movq stack_start(%rip),%rsp
 
        /* zero EFLAGS after setting rsp */
        pushq $0
@@ -208,7 +210,7 @@ ENTRY(secondary_startup_64)
         * addresses where we're currently running on. We have to do that here
         * because in 32bit we couldn't load a 64bit linear address.
         */
-       lgdt    cpu_gdt_descr(%rip)
+       lgdt    early_gdt_descr(%rip)
 
        /* set up data segments. actually 0 would do too */
        movl $__KERNEL_DS,%eax
@@ -257,8 +259,9 @@ ENTRY(secondary_startup_64)
        .quad   x86_64_start_kernel
        __FINITDATA
 
-       ENTRY(init_rsp)
+       ENTRY(stack_start)
        .quad  init_thread_union+THREAD_SIZE-8
+       .word  0
 
 bad_address:
        jmp bad_address
@@ -327,11 +330,11 @@ early_idt_ripmsg:
 ENTRY(name)
 
 /* Automate the creation of 1 to 1 mapping pmd entries */
-#define PMDS(START, PERM, COUNT)               \
-       i = 0 ;                                 \
-       .rept (COUNT) ;                         \
-       .quad   (START) + (i << 21) + (PERM) ;  \
-       i = i + 1 ;                             \
+#define PMDS(START, PERM, COUNT)                       \
+       i = 0 ;                                         \
+       .rept (COUNT) ;                                 \
+       .quad   (START) + (i << PMD_SHIFT) + (PERM) ;   \
+       i = i + 1 ;                                     \
        .endr
 
        /*
@@ -342,9 +345,9 @@ ENTRY(name)
         */
 NEXT_PAGE(init_level4_pgt)
        .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
-       .fill   257,8,0
+       .org    init_level4_pgt + L4_PAGE_OFFSET*8, 0
        .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
-       .fill   252,8,0
+       .org    init_level4_pgt + L4_START_KERNEL*8, 0
        /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
        .quad   level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
 
@@ -353,7 +356,7 @@ NEXT_PAGE(level3_ident_pgt)
        .fill   511,8,0
 
 NEXT_PAGE(level3_kernel_pgt)
-       .fill   510,8,0
+       .fill   L3_START_KERNEL,8,0
        /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
        .quad   level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
        .quad   level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
@@ -384,7 +387,7 @@ NEXT_PAGE(level2_kernel_pgt)
         *  If you want to increase this then increase MODULES_VADDR
         *  too.)
         */
-       PMDS(0, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL,
+       PMDS(0, __PAGE_KERNEL_LARGE_EXEC,
                KERNEL_IMAGE_SIZE/PMD_SIZE)
 
 NEXT_PAGE(level2_spare_pgt)
@@ -395,54 +398,16 @@ NEXT_PAGE(level2_spare_pgt)
 
        .data
        .align 16
-       .globl cpu_gdt_descr
-cpu_gdt_descr:
-       .word   gdt_end-cpu_gdt_table-1
-gdt:
-       .quad   cpu_gdt_table
-#ifdef CONFIG_SMP
-       .rept   NR_CPUS-1
-       .word   0
-       .quad   0
-       .endr
-#endif
+       .globl early_gdt_descr
+early_gdt_descr:
+       .word   GDT_ENTRIES*8-1
+       .quad   per_cpu__gdt_page
 
 ENTRY(phys_base)
        /* This must match the first entry in level2_kernel_pgt */
        .quad   0x0000000000000000
 
-/* We need valid kernel segments for data and code in long mode too
- * IRET will check the segment types  kkeil 2000/10/28
- * Also sysret mandates a special GDT layout 
- */
-                               
-       .section .data.page_aligned, "aw"
-       .align PAGE_SIZE
-
-/* The TLS descriptors are currently at a different place compared to i386.
-   Hopefully nobody expects them at a fixed place (Wine?) */
        
-ENTRY(cpu_gdt_table)
-       .quad   0x0000000000000000      /* NULL descriptor */
-       .quad   0x00cf9b000000ffff      /* __KERNEL32_CS */
-       .quad   0x00af9b000000ffff      /* __KERNEL_CS */
-       .quad   0x00cf93000000ffff      /* __KERNEL_DS */
-       .quad   0x00cffb000000ffff      /* __USER32_CS */
-       .quad   0x00cff3000000ffff      /* __USER_DS, __USER32_DS  */
-       .quad   0x00affb000000ffff      /* __USER_CS */
-       .quad   0x0                     /* unused */
-       .quad   0,0                     /* TSS */
-       .quad   0,0                     /* LDT */
-       .quad   0,0,0                   /* three TLS descriptors */ 
-       .quad   0x0000f40000000000      /* node/CPU stored in limit */
-gdt_end:       
-       /* asm/segment.h:GDT_ENTRIES must match this */ 
-       /* This should be a multiple of the cache line size */
-       /* GDTs of other CPUs are now dynamically allocated */
-
-       /* zero the remaining page */
-       .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0
-
        .section .bss, "aw", @nobits
        .align L1_CACHE_BYTES
 ENTRY(idt_table)
index 9b5cfcdfc426cc194365020c061c6c0b46e54083..0ea6a19bfdfead682bbee695f165b05e9e4b9070 100644 (file)
@@ -17,7 +17,7 @@
 
 /* FSEC = 10^-15
    NSEC = 10^-9 */
-#define FSEC_PER_NSEC  1000000
+#define FSEC_PER_NSEC  1000000L
 
 /*
  * HPET address is set in acpi/boot.c, when an ACPI entry exists
@@ -36,26 +36,15 @@ static inline void hpet_writel(unsigned long d, unsigned long a)
 }
 
 #ifdef CONFIG_X86_64
-
 #include <asm/pgtable.h>
-
-static inline void hpet_set_mapping(void)
-{
-       set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
-       __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
-       hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
-}
-
-static inline void hpet_clear_mapping(void)
-{
-       hpet_virt_address = NULL;
-}
-
-#else
+#endif
 
 static inline void hpet_set_mapping(void)
 {
        hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+#ifdef CONFIG_X86_64
+       __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
+#endif
 }
 
 static inline void hpet_clear_mapping(void)
@@ -63,7 +52,6 @@ static inline void hpet_clear_mapping(void)
        iounmap(hpet_virt_address);
        hpet_virt_address = NULL;
 }
-#endif
 
 /*
  * HPET command line enable / disable
@@ -206,20 +194,19 @@ static void hpet_enable_legacy_int(void)
 
 static void hpet_legacy_clockevent_register(void)
 {
-       uint64_t hpet_freq;
-
        /* Start HPET legacy interrupts */
        hpet_enable_legacy_int();
 
        /*
-        * The period is a femto seconds value. We need to calculate the
-        * scaled math multiplication factor for nanosecond to hpet tick
-        * conversion.
+        * The mult factor is defined as (include/linux/clockchips.h)
+        *  mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h)
+        * hpet_period is in units of femtoseconds (per cycle), so
+        *  mult/2^shift = cyc/ns = 10^6/hpet_period
+        *  mult = (10^6 * 2^shift)/hpet_period
+        *  mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period
         */
-       hpet_freq = 1000000000000000ULL;
-       do_div(hpet_freq, hpet_period);
-       hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
-                                     NSEC_PER_SEC, hpet_clockevent.shift);
+       hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC,
+                                     hpet_period, hpet_clockevent.shift);
        /* Calculate the min / max delta */
        hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
                                                           &hpet_clockevent);
@@ -324,7 +311,7 @@ static struct clocksource clocksource_hpet = {
 
 static int hpet_clocksource_register(void)
 {
-       u64 tmp, start, now;
+       u64 start, now;
        cycle_t t1;
 
        /* Start the counter */
@@ -351,21 +338,15 @@ static int hpet_clocksource_register(void)
                return -ENODEV;
        }
 
-       /* Initialize and register HPET clocksource
-        *
-        * hpet period is in femto seconds per cycle
-        * so we need to convert this to ns/cyc units
-        * approximated by mult/2^shift
-        *
-        *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
-        *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
-        *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
-        *  (fsec/cyc << shift)/1000000 = mult
-        *  (hpet_period << shift)/FSEC_PER_NSEC = mult
+       /*
+        * The definition of mult is (include/linux/clocksource.h)
+        * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc
+        * so we first need to convert hpet_period to ns/cyc units:
+        *  mult/2^shift = ns/cyc = hpet_period/10^6
+        *  mult = (hpet_period * 2^shift)/10^6
+        *  mult = (hpet_period << shift)/FSEC_PER_NSEC
         */
-       tmp = (u64)hpet_period << HPET_SHIFT;
-       do_div(tmp, FSEC_PER_NSEC);
-       clocksource_hpet.mult = (u32)tmp;
+       clocksource_hpet.mult = div_sc(hpet_period, FSEC_PER_NSEC, HPET_SHIFT);
 
        clocksource_register(&clocksource_hpet);
 
index 95e80e5033c3b5c36fb66fd5ac7be4d99f04d421..eb9ddd8efb828175e7be0efcc0616257c67c5943 100644 (file)
@@ -162,7 +162,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset,
        int ret;
 
        if (!cpu_has_fxsr)
-               return -EIO;
+               return -ENODEV;
 
        ret = init_fpu(target);
        if (ret)
@@ -179,7 +179,7 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
        int ret;
 
        if (!cpu_has_fxsr)
-               return -EIO;
+               return -ENODEV;
 
        ret = init_fpu(target);
        if (ret)
similarity index 70%
rename from arch/x86/kernel/i8259_32.c
rename to arch/x86/kernel/i8259.c
index fe631967d6255e3f27a675346f23359153a95299..dc92b49d9204d59d181bcaf01c434446d55de39a 100644 (file)
@@ -1,8 +1,10 @@
+#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/sysdev.h>
 #include <linux/bitops.h>
 
+#include <asm/acpi.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/timer.h>
+#include <asm/hw_irq.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
@@ -32,7 +36,7 @@ static int i8259A_auto_eoi;
 DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
-static struct irq_chip i8259A_chip = {
+struct irq_chip i8259A_chip = {
        .name           = "XT-PIC",
        .mask           = disable_8259A_irq,
        .disable        = disable_8259A_irq,
@@ -125,14 +129,14 @@ static inline int i8259A_irq_real(unsigned int irq)
        int irqmask = 1<<irq;
 
        if (irq < 8) {
-               outb(0x0B,PIC_MASTER_CMD);      /* ISR register */
+               outb(0x0B, PIC_MASTER_CMD);     /* ISR register */
                value = inb(PIC_MASTER_CMD) & irqmask;
-               outb(0x0A,PIC_MASTER_CMD);      /* back to the IRR register */
+               outb(0x0A, PIC_MASTER_CMD);     /* back to the IRR register */
                return value;
        }
-       outb(0x0B,PIC_SLAVE_CMD);       /* ISR register */
+       outb(0x0B, PIC_SLAVE_CMD);      /* ISR register */
        value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
-       outb(0x0A,PIC_SLAVE_CMD);       /* back to the IRR register */
+       outb(0x0A, PIC_SLAVE_CMD);      /* back to the IRR register */
        return value;
 }
 
@@ -171,12 +175,14 @@ handle_real_irq:
        if (irq & 8) {
                inb(PIC_SLAVE_IMR);     /* DUMMY - (do we need this?) */
                outb(cached_slave_mask, PIC_SLAVE_IMR);
-               outb(0x60+(irq&7),PIC_SLAVE_CMD);/* 'Specific EOI' to slave */
-               outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */
+               /* 'Specific EOI' to slave */
+               outb(0x60+(irq&7), PIC_SLAVE_CMD);
+                /* 'Specific EOI' to master-IRQ2 */
+               outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD);
        } else {
                inb(PIC_MASTER_IMR);    /* DUMMY - (do we need this?) */
                outb(cached_master_mask, PIC_MASTER_IMR);
-               outb(0x60+irq,PIC_MASTER_CMD);  /* 'Specific EOI to master */
+               outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */
        }
        spin_unlock_irqrestore(&i8259A_lock, flags);
        return;
@@ -199,7 +205,8 @@ spurious_8259A_irq:
                 * lets ACK and report it. [once per IRQ]
                 */
                if (!(spurious_irq_mask & irqmask)) {
-                       printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
+                       printk(KERN_DEBUG
+                              "spurious 8259A interrupt: IRQ%d.\n", irq);
                        spurious_irq_mask |= irqmask;
                }
                atomic_inc(&irq_err_count);
@@ -290,17 +297,28 @@ void init_8259A(int auto_eoi)
         * outb_pic - this has to work on a wide range of PC hardware.
         */
        outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
-       outb_pic(0x20 + 0, PIC_MASTER_IMR);     /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
-       outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */
+
+       /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 on x86-64,
+                              to 0x20-0x27 on i386 */
+       outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);
+
+       /* 8259A-1 (the master) has a slave on IR2 */
+       outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
+
        if (auto_eoi)   /* master does Auto EOI */
                outb_pic(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
        else            /* master expects normal EOI */
                outb_pic(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
 
        outb_pic(0x11, PIC_SLAVE_CMD);  /* ICW1: select 8259A-2 init */
-       outb_pic(0x20 + 8, PIC_SLAVE_IMR);      /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
-       outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);        /* 8259A-2 is a slave on master's IR2 */
-       outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
+
+       /* ICW2: 8259A-2 IR0-7 mapped to IRQ8_VECTOR */
+       outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);
+       /* 8259A-2 is a slave on master's IR2 */
+       outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
+       /* (slave's support for AEOI in flat mode is to be investigated) */
+       outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
+
        if (auto_eoi)
                /*
                 * In AEOI mode we just have to mask the interrupt
@@ -317,93 +335,3 @@ void init_8259A(int auto_eoi)
 
        spin_unlock_irqrestore(&i8259A_lock, flags);
 }
-
-/*
- * 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
- * (ie as explained in the intel literature). On a 386, you
- * can't use exception 16 due to bad IBM design, so we have to
- * rely on the less exact irq13.
- *
- * Careful.. Not only is IRQ13 unreliable, but it is also
- * leads to races. IBM designers who came up with it should
- * be shot.
- */
-
-static irqreturn_t math_error_irq(int cpl, void *dev_id)
-{
-       extern void math_error(void __user *);
-       outb(0,0xF0);
-       if (ignore_fpu_irq || !boot_cpu_data.hard_math)
-               return IRQ_NONE;
-       math_error((void __user *)get_irq_regs()->ip);
-       return IRQ_HANDLED;
-}
-
-/*
- * New motherboards sometimes make IRQ 13 be a PCI interrupt,
- * so allow interrupt sharing.
- */
-static struct irqaction fpu_irq = {
-       .handler = math_error_irq,
-       .mask = CPU_MASK_NONE,
-       .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 < 16; i++) {
-               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")));
-
-void __init native_init_IRQ(void)
-{
-       int i;
-
-       /* all the set up before the call gates are initialised */
-       pre_intr_init_hook();
-
-       /*
-        * 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 (i >= NR_IRQS)
-                       break;
-               /* SYSCALL_VECTOR was reserved in trap_init. */
-               if (!test_bit(vector, used_vectors))
-                       set_intr_gate(vector, interrupt[i]);
-       }
-
-       /* setup after call gates are initialised (usually add in
-        * the architecture specific gates)
-        */
-       intr_init_hook();
-
-       /*
-        * External FPU? Set up irq13 if so, for
-        * original braindamaged IBM FERR coupling.
-        */
-       if (boot_cpu_data.hard_math && !cpu_has_fpu)
-               setup_irq(FPU_IRQ, &fpu_irq);
-
-       irq_ctx_init(smp_processor_id());
-}
diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c
deleted file mode 100644 (file)
index fa57a15..0000000
+++ /dev/null
@@ -1,512 +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 <asm/acpi.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/hw_irq.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/desc.h>
-#include <asm/apic.h>
-#include <asm/i8259.h>
-
-/*
- * Common place to define all x86 IRQ vectors
- *
- * This builds up the IRQ handler stubs using some ugly macros in irq.h
- *
- * These macros create the low-level assembly IRQ routines that save
- * register context and call do_IRQ(). do_IRQ() then does all the
- * operations that are needed to keep the AT (or SMP IOAPIC)
- * interrupt-controller happy.
- */
-
-#define BI(x,y) \
-       BUILD_IRQ(x##y)
-
-#define BUILD_16_IRQS(x) \
-       BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
-       BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
-       BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
-       BI(x,c) BI(x,d) BI(x,e) BI(x,f)
-
-/*
- * 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)
- */
-                                     BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
-BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
-BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
-
-#undef BUILD_16_IRQS
-#undef BI
-
-
-#define IRQ(x,y) \
-       IRQ##x##y##_interrupt
-
-#define IRQLIST_16(x) \
-       IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
-       IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
-       IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
-       IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
-
-/* for the irq vectors */
-static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = {
-                                         IRQLIST_16(0x2), IRQLIST_16(0x3),
-       IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
-       IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
-       IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
-};
-
-#undef IRQ
-#undef IRQLIST_16
-
-/*
- * This is the 'legacy' 8259A Programmable Interrupt Controller,
- * present in the majority of PC/AT boxes.
- * plus some generic x86 specific things if generic specifics makes
- * any sense at all.
- * this file should become arch/i386/kernel/irq.c when the old irq.c
- * moves to arch independent land
- */
-
-static int i8259A_auto_eoi;
-DEFINE_SPINLOCK(i8259A_lock);
-static void mask_and_ack_8259A(unsigned int);
-
-static struct irq_chip i8259A_chip = {
-       .name           = "XT-PIC",
-       .mask           = disable_8259A_irq,
-       .disable        = disable_8259A_irq,
-       .unmask         = enable_8259A_irq,
-       .mask_ack       = mask_and_ack_8259A,
-};
-
-/*
- * 8259A PIC functions to handle ISA devices:
- */
-
-/*
- * This contains the irq mask for both 8259A irq controllers,
- */
-unsigned int cached_irq_mask = 0xffff;
-
-/*
- * Not all IRQs can be routed through the IO-APIC, eg. on certain (older)
- * boards the timer interrupt is not really connected to any IO-APIC pin,
- * it's fed to the master 8259A's IR0 line only.
- *
- * Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
- * this 'mixed mode' IRQ handling costs nothing because it's only used
- * at IRQ setup time.
- */
-unsigned long io_apic_irqs;
-
-void disable_8259A_irq(unsigned int irq)
-{
-       unsigned int mask = 1 << irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8259A_lock, flags);
-       cached_irq_mask |= mask;
-       if (irq & 8)
-               outb(cached_slave_mask, PIC_SLAVE_IMR);
-       else
-               outb(cached_master_mask, PIC_MASTER_IMR);
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-}
-
-void enable_8259A_irq(unsigned int irq)
-{
-       unsigned int mask = ~(1 << irq);
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8259A_lock, flags);
-       cached_irq_mask &= mask;
-       if (irq & 8)
-               outb(cached_slave_mask, PIC_SLAVE_IMR);
-       else
-               outb(cached_master_mask, PIC_MASTER_IMR);
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-}
-
-int i8259A_irq_pending(unsigned int irq)
-{
-       unsigned int mask = 1<<irq;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&i8259A_lock, flags);
-       if (irq < 8)
-               ret = inb(PIC_MASTER_CMD) & mask;
-       else
-               ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-
-       return ret;
-}
-
-void make_8259A_irq(unsigned int irq)
-{
-       disable_irq_nosync(irq);
-       io_apic_irqs &= ~(1<<irq);
-       set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
-                                     "XT");
-       enable_irq(irq);
-}
-
-/*
- * This function assumes to be called rarely. Switching between
- * 8259A registers is slow.
- * This has to be protected by the irq controller spinlock
- * before being called.
- */
-static inline int i8259A_irq_real(unsigned int irq)
-{
-       int value;
-       int irqmask = 1<<irq;
-
-       if (irq < 8) {
-               outb(0x0B,PIC_MASTER_CMD);      /* ISR register */
-               value = inb(PIC_MASTER_CMD) & irqmask;
-               outb(0x0A,PIC_MASTER_CMD);      /* back to the IRR register */
-               return value;
-       }
-       outb(0x0B,PIC_SLAVE_CMD);       /* ISR register */
-       value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
-       outb(0x0A,PIC_SLAVE_CMD);       /* back to the IRR register */
-       return value;
-}
-
-/*
- * Careful! The 8259A is a fragile beast, it pretty
- * much _has_ to be done exactly like this (mask it
- * first, _then_ send the EOI, and the order of EOI
- * to the two 8259s is important!
- */
-static void mask_and_ack_8259A(unsigned int irq)
-{
-       unsigned int irqmask = 1 << irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8259A_lock, flags);
-       /*
-        * Lightweight spurious IRQ detection. We do not want
-        * to overdo spurious IRQ handling - it's usually a sign
-        * of hardware problems, so we only do the checks we can
-        * do without slowing down good hardware unnecessarily.
-        *
-        * Note that IRQ7 and IRQ15 (the two spurious IRQs
-        * usually resulting from the 8259A-1|2 PICs) occur
-        * even if the IRQ is masked in the 8259A. Thus we
-        * can check spurious 8259A IRQs without doing the
-        * quite slow i8259A_irq_real() call for every IRQ.
-        * This does not cover 100% of spurious interrupts,
-        * but should be enough to warn the user that there
-        * is something bad going on ...
-        */
-       if (cached_irq_mask & irqmask)
-               goto spurious_8259A_irq;
-       cached_irq_mask |= irqmask;
-
-handle_real_irq:
-       if (irq & 8) {
-               inb(PIC_SLAVE_IMR);     /* DUMMY - (do we need this?) */
-               outb(cached_slave_mask, PIC_SLAVE_IMR);
-               /* 'Specific EOI' to slave */
-               outb(0x60+(irq&7),PIC_SLAVE_CMD);
-                /* 'Specific EOI' to master-IRQ2 */
-               outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD);
-       } else {
-               inb(PIC_MASTER_IMR);    /* DUMMY - (do we need this?) */
-               outb(cached_master_mask, PIC_MASTER_IMR);
-               /* 'Specific EOI' to master */
-               outb(0x60+irq,PIC_MASTER_CMD);
-       }
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-       return;
-
-spurious_8259A_irq:
-       /*
-        * this is the slow path - should happen rarely.
-        */
-       if (i8259A_irq_real(irq))
-               /*
-                * oops, the IRQ _is_ in service according to the
-                * 8259A - not spurious, go handle it.
-                */
-               goto handle_real_irq;
-
-       {
-               static int spurious_irq_mask;
-               /*
-                * At this point we can be sure the IRQ is spurious,
-                * lets ACK and report it. [once per IRQ]
-                */
-               if (!(spurious_irq_mask & irqmask)) {
-                       printk(KERN_DEBUG
-                              "spurious 8259A interrupt: IRQ%d.\n", irq);
-                       spurious_irq_mask |= irqmask;
-               }
-               atomic_inc(&irq_err_count);
-               /*
-                * Theoretically we do not have to handle this IRQ,
-                * but in Linux this does not cause problems and is
-                * simpler for us.
-                */
-               goto handle_real_irq;
-       }
-}
-
-static char irq_trigger[2];
-/**
- * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
- */
-static void restore_ELCR(char *trigger)
-{
-       outb(trigger[0], 0x4d0);
-       outb(trigger[1], 0x4d1);
-}
-
-static void save_ELCR(char *trigger)
-{
-       /* IRQ 0,1,2,8,13 are marked as reserved */
-       trigger[0] = inb(0x4d0) & 0xF8;
-       trigger[1] = inb(0x4d1) & 0xDE;
-}
-
-static int i8259A_resume(struct sys_device *dev)
-{
-       init_8259A(i8259A_auto_eoi);
-       restore_ELCR(irq_trigger);
-       return 0;
-}
-
-static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
-{
-       save_ELCR(irq_trigger);
-       return 0;
-}
-
-static int i8259A_shutdown(struct sys_device *dev)
-{
-       /* Put the i8259A into a quiescent state that
-        * the kernel initialization code can get it
-        * out of.
-        */
-       outb(0xff, PIC_MASTER_IMR);     /* mask all of 8259A-1 */
-       outb(0xff, PIC_SLAVE_IMR);      /* mask all of 8259A-1 */
-       return 0;
-}
-
-static struct sysdev_class i8259_sysdev_class = {
-       .name = "i8259",
-       .suspend = i8259A_suspend,
-       .resume = i8259A_resume,
-       .shutdown = i8259A_shutdown,
-};
-
-static struct sys_device device_i8259A = {
-       .id     = 0,
-       .cls    = &i8259_sysdev_class,
-};
-
-static int __init i8259A_init_sysfs(void)
-{
-       int error = sysdev_class_register(&i8259_sysdev_class);
-       if (!error)
-               error = sysdev_register(&device_i8259A);
-       return error;
-}
-
-device_initcall(i8259A_init_sysfs);
-
-void init_8259A(int auto_eoi)
-{
-       unsigned long flags;
-
-       i8259A_auto_eoi = auto_eoi;
-
-       spin_lock_irqsave(&i8259A_lock, flags);
-
-       outb(0xff, PIC_MASTER_IMR);     /* mask all of 8259A-1 */
-       outb(0xff, PIC_SLAVE_IMR);      /* mask all of 8259A-2 */
-
-       /*
-        * outb_pic - this has to work on a wide range of PC hardware.
-        */
-       outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
-       /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */
-       outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);
-       /* 8259A-1 (the master) has a slave on IR2 */
-       outb_pic(0x04, PIC_MASTER_IMR);
-       if (auto_eoi)   /* master does Auto EOI */
-               outb_pic(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
-       else            /* master expects normal EOI */
-               outb_pic(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
-
-       outb_pic(0x11, PIC_SLAVE_CMD);  /* ICW1: select 8259A-2 init */
-       /* ICW2: 8259A-2 IR0-7 mapped to 0x38-0x3f */
-       outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);
-       /* 8259A-2 is a slave on master's IR2 */
-       outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
-       /* (slave's support for AEOI in flat mode is to be investigated) */
-       outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
-
-       if (auto_eoi)
-               /*
-                * In AEOI mode we just have to mask the interrupt
-                * when acking.
-                */
-               i8259A_chip.mask_ack = disable_8259A_irq;
-       else
-               i8259A_chip.mask_ack = mask_and_ack_8259A;
-
-       udelay(100);            /* wait for 8259A to initialize */
-
-       outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
-       outb(cached_slave_mask, PIC_SLAVE_IMR);   /* restore slave IRQ mask */
-
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-}
-
-
-
-
-/*
- * IRQ2 is cascade interrupt to second interrupt controller
- */
-
-static struct irqaction irq2 = {
-       .handler = no_action,
-       .mask = CPU_MASK_NONE,
-       .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
-};
-
-void __init init_ISA_irqs (void)
-{
-       int i;
-
-       init_bsp_APIC();
-       init_8259A(0);
-
-       for (i = 0; i < NR_IRQS; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = NULL;
-               irq_desc[i].depth = 1;
-
-               if (i < 16) {
-                       /*
-                        * 16 old-style INTA-cycle interrupts:
-                        */
-                       set_irq_chip_and_handler_name(i, &i8259A_chip,
-                                                     handle_level_irq, "XT");
-               } else {
-                       /*
-                        * 'high' PCI IRQs filled in on demand
-                        */
-                       irq_desc[i].chip = &no_irq_chip;
-               }
-       }
-}
-
-void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
-
-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]);
-       }
-
-#ifdef CONFIG_SMP
-       /*
-        * The reschedule interrupt is a CPU-to-CPU reschedule-helper
-        * IPI, driven by wakeup.
-        */
-       set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
-
-       /* IPIs for invalidation */
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
-       set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
-
-       /* IPI for generic function call */
-       set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-
-       /* Low priority IPI to cleanup after moving an irq */
-       set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
-#endif
-       set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
-       set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
-
-       /* self generated IPI for local APIC timer */
-       set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
-
-       /* IPI vectors for APIC spurious and error interrupts */
-       set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-       set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
-
-       if (!acpi_ioapic)
-               setup_irq(2, &irq2);
-}
index 4dc8600d9d2072ed5ed79ee3884f70afd2281636..603261a5885cf2a1e1f55be2845197641e1a2d61 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/bootmem.h>
 #include <linux/mc146818rtc.h>
 #include <linux/compiler.h>
 #include <linux/acpi.h>
@@ -58,7 +59,7 @@ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
 static DEFINE_SPINLOCK(ioapic_lock);
 static DEFINE_SPINLOCK(vector_lock);
 
-int timer_over_8254 __initdata = 1;
+int timer_through_8259 __initdata;
 
 /*
  *     Is the SiS APIC rmw bug present ?
@@ -72,15 +73,21 @@ int sis_apic_bug = -1;
 int nr_ioapic_registers[MAX_IO_APICS];
 
 /* I/O APIC entries */
-struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
 int nr_ioapics;
 
 /* MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
 
 /* # of MP IRQ source entries */
 int mp_irq_entries;
 
+#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
+int mp_bus_id_to_type[MAX_MP_BUSSES];
+#endif
+
+DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
+
 static int disable_timer_pin_1 __initdata;
 
 /*
@@ -110,7 +117,7 @@ struct io_apic {
 static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
 {
        return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
-               + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK);
+               + (mp_ioapics[idx].mp_apicaddr & ~PAGE_MASK);
 }
 
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
@@ -239,7 +246,7 @@ static void __init replace_pin_at_irq(unsigned int irq,
        }
 }
 
-static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable)
+static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable)
 {
        struct irq_pin_list *entry = irq_2_pin + irq;
        unsigned int pin, reg;
@@ -259,30 +266,32 @@ static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsign
 }
 
 /* mask = 1 */
-static void __mask_IO_APIC_irq (unsigned int irq)
+static void __mask_IO_APIC_irq(unsigned int irq)
 {
-       __modify_IO_APIC_irq(irq, 0x00010000, 0);
+       __modify_IO_APIC_irq(irq, IO_APIC_REDIR_MASKED, 0);
 }
 
 /* mask = 0 */
-static void __unmask_IO_APIC_irq (unsigned int irq)
+static void __unmask_IO_APIC_irq(unsigned int irq)
 {
-       __modify_IO_APIC_irq(irq, 0, 0x00010000);
+       __modify_IO_APIC_irq(irq, 0, IO_APIC_REDIR_MASKED);
 }
 
 /* mask = 1, trigger = 0 */
-static void __mask_and_edge_IO_APIC_irq (unsigned int irq)
+static void __mask_and_edge_IO_APIC_irq(unsigned int irq)
 {
-       __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000);
+       __modify_IO_APIC_irq(irq, IO_APIC_REDIR_MASKED,
+                               IO_APIC_REDIR_LEVEL_TRIGGER);
 }
 
 /* mask = 0, trigger = 1 */
-static void __unmask_and_level_IO_APIC_irq (unsigned int irq)
+static void __unmask_and_level_IO_APIC_irq(unsigned int irq)
 {
-       __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000);
+       __modify_IO_APIC_irq(irq, IO_APIC_REDIR_LEVEL_TRIGGER,
+                               IO_APIC_REDIR_MASKED);
 }
 
-static void mask_IO_APIC_irq (unsigned int irq)
+static void mask_IO_APIC_irq(unsigned int irq)
 {
        unsigned long flags;
 
@@ -291,7 +300,7 @@ static void mask_IO_APIC_irq (unsigned int irq)
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void unmask_IO_APIC_irq (unsigned int irq)
+static void unmask_IO_APIC_irq(unsigned int irq)
 {
        unsigned long flags;
 
@@ -303,7 +312,7 @@ static void unmask_IO_APIC_irq (unsigned int irq)
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
        struct IO_APIC_route_entry entry;
-       
+
        /* Check delivery_mode to be sure we're not clearing an SMI pin */
        entry = ioapic_read_entry(apic, pin);
        if (entry.delivery_mode == dest_SMI)
@@ -315,7 +324,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
        ioapic_mask_entry(apic, pin);
 }
 
-static void clear_IO_APIC (void)
+static void clear_IO_APIC(void)
 {
        int apic, pin;
 
@@ -332,7 +341,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
        struct irq_pin_list *entry = irq_2_pin + irq;
        unsigned int apicid_value;
        cpumask_t tmp;
-       
+
        cpus_and(tmp, cpumask, cpu_online_map);
        if (cpus_empty(tmp))
                tmp = TARGET_CPUS;
@@ -361,7 +370,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
 # include <linux/kernel_stat.h>        /* kstat */
 # include <linux/slab.h>               /* kmalloc() */
 # include <linux/timer.h>
+
 #define IRQBALANCE_CHECK_ARCH -999
 #define MAX_BALANCED_IRQ_INTERVAL      (5*HZ)
 #define MIN_BALANCED_IRQ_INTERVAL      (HZ/2)
@@ -373,14 +382,14 @@ static int physical_balance __read_mostly;
 static long balanced_irq_interval __read_mostly = MAX_BALANCED_IRQ_INTERVAL;
 
 static struct irq_cpu_info {
-       unsigned long * last_irq;
-       unsigned long * irq_delta;
+       unsigned long *last_irq;
+       unsigned long *irq_delta;
        unsigned long irq;
 } irq_cpu_data[NR_CPUS];
 
 #define CPU_IRQ(cpu)           (irq_cpu_data[cpu].irq)
-#define LAST_CPU_IRQ(cpu,irq)   (irq_cpu_data[cpu].last_irq[irq])
-#define IRQ_DELTA(cpu,irq)     (irq_cpu_data[cpu].irq_delta[irq])
+#define LAST_CPU_IRQ(cpu, irq)   (irq_cpu_data[cpu].last_irq[irq])
+#define IRQ_DELTA(cpu, irq)    (irq_cpu_data[cpu].irq_delta[irq])
 
 #define IDLE_ENOUGH(cpu,now) \
        (idle_cpu(cpu) && ((now) - per_cpu(irq_stat, (cpu)).idle_timestamp > 1))
@@ -419,8 +428,8 @@ inside:
                        if (cpu == -1)
                                cpu = NR_CPUS-1;
                }
-       } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) ||
-                       (search_idle && !IDLE_ENOUGH(cpu,now)));
+       } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu, allowed_mask) ||
+                       (search_idle && !IDLE_ENOUGH(cpu, now)));
 
        return cpu;
 }
@@ -430,15 +439,14 @@ static inline void balance_irq(int cpu, int irq)
        unsigned long now = jiffies;
        cpumask_t allowed_mask;
        unsigned int new_cpu;
-               
+
        if (irqbalance_disabled)
-               return; 
+               return;
 
        cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[irq]);
        new_cpu = move(cpu, allowed_mask, now, 1);
-       if (cpu != new_cpu) {
+       if (cpu != new_cpu)
                set_pending_irq(irq, cpumask_of_cpu(new_cpu));
-       }
 }
 
 static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
@@ -450,14 +458,14 @@ static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
                        if (!irq_desc[j].action)
                                continue;
                        /* Is it a significant load ?  */
-                       if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) <
+                       if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i), j) <
                                                useful_load_threshold)
                                continue;
                        balance_irq(i, j);
                }
        }
        balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
-               balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);       
+               balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
        return;
 }
 
@@ -486,22 +494,22 @@ static void do_irq_balance(void)
                        /* Is this an active IRQ or balancing disabled ? */
                        if (!irq_desc[j].action || irq_balancing_disabled(j))
                                continue;
-                       if ( package_index == i )
-                               IRQ_DELTA(package_index,j) = 0;
+                       if (package_index == i)
+                               IRQ_DELTA(package_index, j) = 0;
                        /* Determine the total count per processor per IRQ */
                        value_now = (unsigned long) kstat_cpu(i).irqs[j];
 
                        /* Determine the activity per processor per IRQ */
-                       delta = value_now - LAST_CPU_IRQ(i,j);
+                       delta = value_now - LAST_CPU_IRQ(i, j);
 
                        /* Update last_cpu_irq[][] for the next time */
-                       LAST_CPU_IRQ(i,j) = value_now;
+                       LAST_CPU_IRQ(i, j) = value_now;
 
                        /* Ignore IRQs whose rate is less than the clock */
                        if (delta < useful_load_threshold)
                                continue;
                        /* update the load for the processor or package total */
-                       IRQ_DELTA(package_index,j) += delta;
+                       IRQ_DELTA(package_index, j) += delta;
 
                        /* Keep track of the higher numbered sibling as well */
                        if (i != package_index)
@@ -527,7 +535,8 @@ static void do_irq_balance(void)
        max_cpu_irq = ULONG_MAX;
 
 tryanothercpu:
-       /* Look for heaviest loaded processor.
+       /*
+        * Look for heaviest loaded processor.
         * We may come back to get the next heaviest loaded processor.
         * Skip processors with trivial loads.
         */
@@ -536,7 +545,7 @@ tryanothercpu:
        for_each_online_cpu(i) {
                if (i != CPU_TO_PACKAGEINDEX(i))
                        continue;
-               if (max_cpu_irq <= CPU_IRQ(i)) 
+               if (max_cpu_irq <= CPU_IRQ(i))
                        continue;
                if (tmp_cpu_irq < CPU_IRQ(i)) {
                        tmp_cpu_irq = CPU_IRQ(i);
@@ -545,8 +554,9 @@ tryanothercpu:
        }
 
        if (tmp_loaded == -1) {
-        /* In the case of small number of heavy interrupt sources, 
-         * loading some of the cpus too much. We use Ingo's original 
+        /*
+         * In the case of small number of heavy interrupt sources,
+         * loading some of the cpus too much. We use Ingo's original
          * approach to rotate them around.
          */
                if (!first_attempt && imbalance >= useful_load_threshold) {
@@ -555,13 +565,14 @@ tryanothercpu:
                }
                goto not_worth_the_effort;
        }
-       
+
        first_attempt = 0;              /* heaviest search */
        max_cpu_irq = tmp_cpu_irq;      /* load */
        max_loaded = tmp_loaded;        /* processor */
        imbalance = (max_cpu_irq - min_cpu_irq) / 2;
-       
-       /* if imbalance is less than approx 10% of max load, then
+
+       /*
+        * if imbalance is less than approx 10% of max load, then
         * observe diminishing returns action. - quit
         */
        if (imbalance < (max_cpu_irq >> 3))
@@ -577,26 +588,25 @@ tryanotherirq:
                /* Is this an active IRQ? */
                if (!irq_desc[j].action)
                        continue;
-               if (imbalance <= IRQ_DELTA(max_loaded,j))
+               if (imbalance <= IRQ_DELTA(max_loaded, j))
                        continue;
                /* Try to find the IRQ that is closest to the imbalance
                 * without going over.
                 */
-               if (move_this_load < IRQ_DELTA(max_loaded,j)) {
-                       move_this_load = IRQ_DELTA(max_loaded,j);
+               if (move_this_load < IRQ_DELTA(max_loaded, j)) {
+                       move_this_load = IRQ_DELTA(max_loaded, j);
                        selected_irq = j;
                }
        }
-       if (selected_irq == -1) {
+       if (selected_irq == -1)
                goto tryanothercpu;
-       }
 
        imbalance = move_this_load;
-       
+
        /* For physical_balance case, we accumulated both load
         * values in the one of the siblings cpu_irq[],
         * to use the same code for physical and logical processors
-        * as much as possible. 
+        * as much as possible.
         *
         * NOTE: the cpu_irq[] array holds the sum of the load for
         * sibling A and sibling B in the slot for the lowest numbered
@@ -625,11 +635,11 @@ tryanotherirq:
                /* mark for change destination */
                set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
 
-               /* Since we made a change, come back sooner to 
+               /* Since we made a change, come back sooner to
                 * check for more variation.
                 */
                balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
-                       balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);       
+                       balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
                return;
        }
        goto tryanotherirq;
@@ -640,7 +650,7 @@ not_worth_the_effort:
         * upward
         */
        balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
-               balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);       
+               balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);
        return;
 }
 
@@ -679,13 +689,13 @@ static int __init balanced_irq_init(void)
        cpumask_t tmp;
 
        cpus_shift_right(tmp, cpu_online_map, 2);
-        c = &boot_cpu_data;
+       c = &boot_cpu_data;
        /* When not overwritten by the command line ask subarchitecture. */
        if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
                irqbalance_disabled = NO_BALANCE_IRQ;
        if (irqbalance_disabled)
                return 0;
-       
+
         /* disable irqbalance completely if there is only one processor online */
        if (num_online_cpus() < 2) {
                irqbalance_disabled = 1;
@@ -699,16 +709,14 @@ static int __init balanced_irq_init(void)
                physical_balance = 1;
 
        for_each_online_cpu(i) {
-               irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
-               irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
+               irq_cpu_data[i].irq_delta = kzalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
+               irq_cpu_data[i].last_irq = kzalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
                if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) {
                        printk(KERN_ERR "balanced_irq_init: out of memory");
                        goto failed;
                }
-               memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS);
-               memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS);
        }
-       
+
        printk(KERN_INFO "Starting balanced_irq\n");
        if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd")))
                return 0;
@@ -801,10 +809,10 @@ static int find_irq_entry(int apic, int pin, int type)
        int i;
 
        for (i = 0; i < mp_irq_entries; i++)
-               if (mp_irqs[i].mpc_irqtype == type &&
-                   (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
-                    mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
-                   mp_irqs[i].mpc_dstirq == pin)
+               if (mp_irqs[i].mp_irqtype == type &&
+                   (mp_irqs[i].mp_dstapic == mp_ioapics[apic].mp_apicid ||
+                    mp_irqs[i].mp_dstapic == MP_APIC_ALL) &&
+                   mp_irqs[i].mp_dstirq == pin)
                        return i;
 
        return -1;
@@ -818,13 +826,13 @@ static int __init find_isa_irq_pin(int irq, int type)
        int i;
 
        for (i = 0; i < mp_irq_entries; i++) {
-               int lbus = mp_irqs[i].mpc_srcbus;
+               int lbus = mp_irqs[i].mp_srcbus;
 
                if (test_bit(lbus, mp_bus_not_pci) &&
-                   (mp_irqs[i].mpc_irqtype == type) &&
-                   (mp_irqs[i].mpc_srcbusirq == irq))
+                   (mp_irqs[i].mp_irqtype == type) &&
+                   (mp_irqs[i].mp_srcbusirq == irq))
 
-                       return mp_irqs[i].mpc_dstirq;
+                       return mp_irqs[i].mp_dstirq;
        }
        return -1;
 }
@@ -834,17 +842,17 @@ static int __init find_isa_irq_apic(int irq, int type)
        int i;
 
        for (i = 0; i < mp_irq_entries; i++) {
-               int lbus = mp_irqs[i].mpc_srcbus;
+               int lbus = mp_irqs[i].mp_srcbus;
 
                if (test_bit(lbus, mp_bus_not_pci) &&
-                   (mp_irqs[i].mpc_irqtype == type) &&
-                   (mp_irqs[i].mpc_srcbusirq == irq))
+                   (mp_irqs[i].mp_irqtype == type) &&
+                   (mp_irqs[i].mp_srcbusirq == irq))
                        break;
        }
        if (i < mp_irq_entries) {
                int apic;
-               for(apic = 0; apic < nr_ioapics; apic++) {
-                       if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+               for (apic = 0; apic < nr_ioapics; apic++) {
+                       if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic)
                                return apic;
                }
        }
@@ -864,28 +872,28 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
 
        apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, "
                "slot:%d, pin:%d.\n", bus, slot, pin);
-       if (mp_bus_id_to_pci_bus[bus] == -1) {
+       if (test_bit(bus, mp_bus_not_pci)) {
                printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
                return -1;
        }
        for (i = 0; i < mp_irq_entries; i++) {
-               int lbus = mp_irqs[i].mpc_srcbus;
+               int lbus = mp_irqs[i].mp_srcbus;
 
                for (apic = 0; apic < nr_ioapics; apic++)
-                       if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||
-                           mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
+                       if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic ||
+                           mp_irqs[i].mp_dstapic == MP_APIC_ALL)
                                break;
 
                if (!test_bit(lbus, mp_bus_not_pci) &&
-                   !mp_irqs[i].mpc_irqtype &&
+                   !mp_irqs[i].mp_irqtype &&
                    (bus == lbus) &&
-                   (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
-                       int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
+                   (slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) {
+                       int irq = pin_2_irq(i, apic, mp_irqs[i].mp_dstirq);
 
                        if (!(apic || IO_APIC_IRQ(irq)))
                                continue;
 
-                       if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
+                       if (pin == (mp_irqs[i].mp_srcbusirq & 3))
                                return irq;
                        /*
                         * Use the first all-but-pin matching entry as a
@@ -900,7 +908,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
 EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
 
 /*
- * This function currently is only a helper for the i386 smp boot process where 
+ * This function currently is only a helper for the i386 smp boot process where
  * we need to reprogram the ioredtbls to cater for the cpus which have come online
  * so mask in all cases should simply be TARGET_CPUS
  */
@@ -952,7 +960,7 @@ static int EISA_ELCR(unsigned int irq)
  * EISA conforming in the MP table, that means its trigger type must
  * be read in from the ELCR */
 
-#define default_EISA_trigger(idx)      (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))
+#define default_EISA_trigger(idx)      (EISA_ELCR(mp_irqs[idx].mp_srcbusirq))
 #define default_EISA_polarity(idx)     default_ISA_polarity(idx)
 
 /* PCI interrupts are always polarity one level triggered,
@@ -969,118 +977,115 @@ static int EISA_ELCR(unsigned int irq)
 
 static int MPBIOS_polarity(int idx)
 {
-       int bus = mp_irqs[idx].mpc_srcbus;
+       int bus = mp_irqs[idx].mp_srcbus;
        int polarity;
 
        /*
         * Determine IRQ line polarity (high active or low active):
         */
-       switch (mp_irqs[idx].mpc_irqflag & 3)
+       switch (mp_irqs[idx].mp_irqflag & 3) {
+       case 0: /* conforms, ie. bus-type dependent polarity */
        {
-               case 0: /* conforms, ie. bus-type dependent polarity */
-               {
-                       polarity = test_bit(bus, mp_bus_not_pci)?
-                               default_ISA_polarity(idx):
-                               default_PCI_polarity(idx);
-                       break;
-               }
-               case 1: /* high active */
-               {
-                       polarity = 0;
-                       break;
-               }
-               case 2: /* reserved */
-               {
-                       printk(KERN_WARNING "broken BIOS!!\n");
-                       polarity = 1;
-                       break;
-               }
-               case 3: /* low active */
-               {
-                       polarity = 1;
-                       break;
-               }
-               default: /* invalid */
-               {
-                       printk(KERN_WARNING "broken BIOS!!\n");
-                       polarity = 1;
-                       break;
-               }
+               polarity = test_bit(bus, mp_bus_not_pci)?
+                       default_ISA_polarity(idx):
+                       default_PCI_polarity(idx);
+               break;
+       }
+       case 1: /* high active */
+       {
+               polarity = 0;
+               break;
+       }
+       case 2: /* reserved */
+       {
+               printk(KERN_WARNING "broken BIOS!!\n");
+               polarity = 1;
+               break;
+       }
+       case 3: /* low active */
+       {
+               polarity = 1;
+               break;
+       }
+       default: /* invalid */
+       {
+               printk(KERN_WARNING "broken BIOS!!\n");
+               polarity = 1;
+               break;
+       }
        }
        return polarity;
 }
 
 static int MPBIOS_trigger(int idx)
 {
-       int bus = mp_irqs[idx].mpc_srcbus;
+       int bus = mp_irqs[idx].mp_srcbus;
        int trigger;
 
        /*
         * Determine IRQ trigger mode (edge or level sensitive):
         */
-       switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
+       switch ((mp_irqs[idx].mp_irqflag>>2) & 3) {
+       case 0: /* conforms, ie. bus-type dependent */
        {
-               case 0: /* conforms, ie. bus-type dependent */
-               {
-                       trigger = test_bit(bus, mp_bus_not_pci)?
-                                       default_ISA_trigger(idx):
-                                       default_PCI_trigger(idx);
+               trigger = test_bit(bus, mp_bus_not_pci)?
+                               default_ISA_trigger(idx):
+                               default_PCI_trigger(idx);
 #if defined(CONFIG_EISA) || defined(CONFIG_MCA)
-                       switch (mp_bus_id_to_type[bus])
-                       {
-                               case MP_BUS_ISA: /* ISA pin */
-                               {
-                                       /* set before the switch */
-                                       break;
-                               }
-                               case MP_BUS_EISA: /* EISA pin */
-                               {
-                                       trigger = default_EISA_trigger(idx);
-                                       break;
-                               }
-                               case MP_BUS_PCI: /* PCI pin */
-                               {
-                                       /* set before the switch */
-                                       break;
-                               }
-                               case MP_BUS_MCA: /* MCA pin */
-                               {
-                                       trigger = default_MCA_trigger(idx);
-                                       break;
-                               }
-                               default:
-                               {
-                                       printk(KERN_WARNING "broken BIOS!!\n");
-                                       trigger = 1;
-                                       break;
-                               }
-                       }
-#endif
+               switch (mp_bus_id_to_type[bus]) {
+               case MP_BUS_ISA: /* ISA pin */
+               {
+                       /* set before the switch */
                        break;
                }
-               case 1: /* edge */
+               case MP_BUS_EISA: /* EISA pin */
                {
-                       trigger = 0;
+                       trigger = default_EISA_trigger(idx);
                        break;
                }
-               case 2: /* reserved */
+               case MP_BUS_PCI: /* PCI pin */
                {
-                       printk(KERN_WARNING "broken BIOS!!\n");
-                       trigger = 1;
+                       /* set before the switch */
                        break;
                }
-               case 3: /* level */
+               case MP_BUS_MCA: /* MCA pin */
                {
-                       trigger = 1;
+                       trigger = default_MCA_trigger(idx);
                        break;
                }
-               default: /* invalid */
+               default:
                {
                        printk(KERN_WARNING "broken BIOS!!\n");
-                       trigger = 0;
+                       trigger = 1;
                        break;
                }
        }
+#endif
+               break;
+       }
+       case 1: /* edge */
+       {
+               trigger = 0;
+               break;
+       }
+       case 2: /* reserved */
+       {
+               printk(KERN_WARNING "broken BIOS!!\n");
+               trigger = 1;
+               break;
+       }
+       case 3: /* level */
+       {
+               trigger = 1;
+               break;
+       }
+       default: /* invalid */
+       {
+               printk(KERN_WARNING "broken BIOS!!\n");
+               trigger = 0;
+               break;
+       }
+       }
        return trigger;
 }
 
@@ -1097,16 +1102,16 @@ static inline int irq_trigger(int idx)
 static int pin_2_irq(int idx, int apic, int pin)
 {
        int irq, i;
-       int bus = mp_irqs[idx].mpc_srcbus;
+       int bus = mp_irqs[idx].mp_srcbus;
 
        /*
         * Debugging check, we are in big trouble if this message pops up!
         */
-       if (mp_irqs[idx].mpc_dstirq != pin)
+       if (mp_irqs[idx].mp_dstirq != pin)
                printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
 
        if (test_bit(bus, mp_bus_not_pci))
-               irq = mp_irqs[idx].mpc_srcbusirq;
+               irq = mp_irqs[idx].mp_srcbusirq;
        else {
                /*
                 * PCI IRQs are mapped in order
@@ -1148,8 +1153,8 @@ static inline int IO_APIC_irq_trigger(int irq)
 
        for (apic = 0; apic < nr_ioapics; apic++) {
                for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
-                       idx = find_irq_entry(apic,pin,mp_INT);
-                       if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+                       idx = find_irq_entry(apic, pin, mp_INT);
+                       if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin)))
                                return irq_trigger(idx);
                }
        }
@@ -1164,7 +1169,7 @@ static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }
 
 static int __assign_irq_vector(int irq)
 {
-       static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
+       static int current_vector = FIRST_DEVICE_VECTOR, current_offset;
        int vector, offset;
 
        BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
@@ -1176,7 +1181,7 @@ static int __assign_irq_vector(int irq)
        offset = current_offset;
 next:
        vector += 8;
-       if (vector >= FIRST_SYSTEM_VECTOR) {
+       if (vector >= first_system_vector) {
                offset = (offset + 1) % 8;
                vector = FIRST_DEVICE_VECTOR + offset;
        }
@@ -1203,6 +1208,11 @@ static int assign_irq_vector(int irq)
 
        return vector;
 }
+
+void setup_vector_irq(int cpu)
+{
+}
+
 static struct irq_chip ioapic_chip;
 
 #define IOAPIC_AUTO    -1
@@ -1237,25 +1247,25 @@ static void __init setup_IO_APIC_irqs(void)
                /*
                 * add it to the IO-APIC irq-routing table:
                 */
-               memset(&entry,0,sizeof(entry));
+               memset(&entry, 0, sizeof(entry));
 
                entry.delivery_mode = INT_DELIVERY_MODE;
                entry.dest_mode = INT_DEST_MODE;
                entry.mask = 0;                         /* enable IRQ */
-               entry.dest.logical.logical_dest = 
+               entry.dest.logical.logical_dest =
                                        cpu_mask_to_apicid(TARGET_CPUS);
 
-               idx = find_irq_entry(apic,pin,mp_INT);
+               idx = find_irq_entry(apic, pin, mp_INT);
                if (idx == -1) {
                        if (first_notcon) {
                                apic_printk(APIC_VERBOSE, KERN_DEBUG
                                                " IO-APIC (apicid-pin) %d-%d",
-                                               mp_ioapics[apic].mpc_apicid,
+                                               mp_ioapics[apic].mp_apicid,
                                                pin);
                                first_notcon = 0;
                        } else
                                apic_printk(APIC_VERBOSE, ", %d-%d",
-                                       mp_ioapics[apic].mpc_apicid, pin);
+                                       mp_ioapics[apic].mp_apicid, pin);
                        continue;
                }
 
@@ -1289,7 +1299,7 @@ static void __init setup_IO_APIC_irqs(void)
                        vector = assign_irq_vector(irq);
                        entry.vector = vector;
                        ioapic_register_intr(irq, vector, IOAPIC_AUTO);
-               
+
                        if (!apic && (irq < 16))
                                disable_8259A_irq(irq);
                }
@@ -1302,25 +1312,21 @@ static void __init setup_IO_APIC_irqs(void)
 }
 
 /*
- * Set up the 8259A-master output pin:
+ * Set up the timer pin, possibly with the 8259A-master behind.
  */
-static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
+static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
+                                       int vector)
 {
        struct IO_APIC_route_entry entry;
 
-       memset(&entry,0,sizeof(entry));
-
-       disable_8259A_irq(0);
-
-       /* mask LVT0 */
-       apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
+       memset(&entry, 0, sizeof(entry));
 
        /*
         * We use logical delivery to get the timer IRQ
         * to the first CPU.
         */
        entry.dest_mode = INT_DEST_MODE;
-       entry.mask = 0;                                 /* unmask IRQ now */
+       entry.mask = 1;                                 /* mask IRQ now */
        entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
        entry.delivery_mode = INT_DELIVERY_MODE;
        entry.polarity = 0;
@@ -1329,17 +1335,14 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
 
        /*
         * The timer IRQ doesn't have to know that behind the
-        * scene we have a 8259A-master in AEOI mode ...
+        * scene we may have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].chip = &ioapic_chip;
-       set_irq_handler(0, handle_edge_irq);
+       ioapic_register_intr(0, vector, IOAPIC_EDGE);
 
        /*
         * Add it to the IO-APIC irq-routing table:
         */
        ioapic_write_entry(apic, pin, entry);
-
-       enable_8259A_irq(0);
 }
 
 void __init print_IO_APIC(void)
@@ -1354,10 +1357,10 @@ void __init print_IO_APIC(void)
        if (apic_verbosity == APIC_QUIET)
                return;
 
-       printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
+       printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
        for (i = 0; i < nr_ioapics; i++)
                printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
-                      mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
+                      mp_ioapics[i].mp_apicid, nr_ioapic_registers[i]);
 
        /*
         * We are a bit conservative about what we expect.  We have to
@@ -1376,7 +1379,7 @@ void __init print_IO_APIC(void)
                reg_03.raw = io_apic_read(apic, 3);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
-       printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
+       printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid);
        printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
        printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
        printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.bits.delivery_type);
@@ -1459,7 +1462,7 @@ void __init print_IO_APIC(void)
 
 #if 0
 
-static void print_APIC_bitfield (int base)
+static void print_APIC_bitfield(int base)
 {
        unsigned int v;
        int i, j;
@@ -1480,7 +1483,7 @@ static void print_APIC_bitfield (int base)
        }
 }
 
-void /*__init*/ print_local_APIC(void * dummy)
+void /*__init*/ print_local_APIC(void *dummy)
 {
        unsigned int v, ver, maxlvt;
 
@@ -1489,6 +1492,7 @@ void /*__init*/ print_local_APIC(void * dummy)
 
        printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
                smp_processor_id(), hard_smp_processor_id());
+       v = apic_read(APIC_ID);
        printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v,
                        GET_APIC_ID(read_apic_id()));
        v = apic_read(APIC_LVR);
@@ -1563,7 +1567,7 @@ void /*__init*/ print_local_APIC(void * dummy)
        printk("\n");
 }
 
-void print_all_local_APICs (void)
+void print_all_local_APICs(void)
 {
        on_each_cpu(print_local_APIC, NULL, 1, 1);
 }
@@ -1586,11 +1590,11 @@ void /*__init*/ print_PIC(void)
        v = inb(0xa0) << 8 | inb(0x20);
        printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);
 
-       outb(0x0b,0xa0);
-       outb(0x0b,0x20);
+       outb(0x0b, 0xa0);
+       outb(0x0b, 0x20);
        v = inb(0xa0) << 8 | inb(0x20);
-       outb(0x0a,0xa0);
-       outb(0x0a,0x20);
+       outb(0x0a, 0xa0);
+       outb(0x0a, 0x20);
 
        spin_unlock_irqrestore(&i8259A_lock, flags);
 
@@ -1626,7 +1630,7 @@ static void __init enable_IO_APIC(void)
                spin_unlock_irqrestore(&ioapic_lock, flags);
                nr_ioapic_registers[apic] = reg_01.bits.entries+1;
        }
-       for(apic = 0; apic < nr_ioapics; apic++) {
+       for (apic = 0; apic < nr_ioapics; apic++) {
                int pin;
                /* See if any of the pins is in ExtINT mode */
                for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
@@ -1716,7 +1720,6 @@ void disable_IO_APIC(void)
  * by Matt Domsch <Matt_Domsch@dell.com>  Tue Dec 21 12:25:05 CST 1999
  */
 
-#ifndef CONFIG_X86_NUMAQ
 static void __init setup_ioapic_ids_from_mpc(void)
 {
        union IO_APIC_reg_00 reg_00;
@@ -1726,6 +1729,11 @@ static void __init setup_ioapic_ids_from_mpc(void)
        unsigned char old_id;
        unsigned long flags;
 
+#ifdef CONFIG_X86_NUMAQ
+       if (found_numaq)
+               return;
+#endif
+
        /*
         * Don't check I/O APIC IDs for xAPIC systems.  They have
         * no meaning without the serial APIC bus.
@@ -1748,15 +1756,15 @@ static void __init setup_ioapic_ids_from_mpc(void)
                spin_lock_irqsave(&ioapic_lock, flags);
                reg_00.raw = io_apic_read(apic, 0);
                spin_unlock_irqrestore(&ioapic_lock, flags);
-               
-               old_id = mp_ioapics[apic].mpc_apicid;
 
-               if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {
+               old_id = mp_ioapics[apic].mp_apicid;
+
+               if (mp_ioapics[apic].mp_apicid >= get_physical_broadcast()) {
                        printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
-                               apic, mp_ioapics[apic].mpc_apicid);
+                               apic, mp_ioapics[apic].mp_apicid);
                        printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
                                reg_00.bits.ID);
-                       mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;
+                       mp_ioapics[apic].mp_apicid = reg_00.bits.ID;
                }
 
                /*
@@ -1765,9 +1773,9 @@ static void __init setup_ioapic_ids_from_mpc(void)
                 * 'stuck on smp_invalidate_needed IPI wait' messages.
                 */
                if (check_apicid_used(phys_id_present_map,
-                                       mp_ioapics[apic].mpc_apicid)) {
+                                       mp_ioapics[apic].mp_apicid)) {
                        printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
-                               apic, mp_ioapics[apic].mpc_apicid);
+                               apic, mp_ioapics[apic].mp_apicid);
                        for (i = 0; i < get_physical_broadcast(); i++)
                                if (!physid_isset(i, phys_id_present_map))
                                        break;
@@ -1776,13 +1784,13 @@ static void __init setup_ioapic_ids_from_mpc(void)
                        printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
                                i);
                        physid_set(i, phys_id_present_map);
-                       mp_ioapics[apic].mpc_apicid = i;
+                       mp_ioapics[apic].mp_apicid = i;
                } else {
                        physid_mask_t tmp;
-                       tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid);
+                       tmp = apicid_to_cpu_present(mp_ioapics[apic].mp_apicid);
                        apic_printk(APIC_VERBOSE, "Setting %d in the "
                                        "phys_id_present_map\n",
-                                       mp_ioapics[apic].mpc_apicid);
+                                       mp_ioapics[apic].mp_apicid);
                        physids_or(phys_id_present_map, phys_id_present_map, tmp);
                }
 
@@ -1791,21 +1799,21 @@ static void __init setup_ioapic_ids_from_mpc(void)
                 * We need to adjust the IRQ routing table
                 * if the ID changed.
                 */
-               if (old_id != mp_ioapics[apic].mpc_apicid)
+               if (old_id != mp_ioapics[apic].mp_apicid)
                        for (i = 0; i < mp_irq_entries; i++)
-                               if (mp_irqs[i].mpc_dstapic == old_id)
-                                       mp_irqs[i].mpc_dstapic
-                                               = mp_ioapics[apic].mpc_apicid;
+                               if (mp_irqs[i].mp_dstapic == old_id)
+                                       mp_irqs[i].mp_dstapic
+                                               = mp_ioapics[apic].mp_apicid;
 
                /*
                 * Read the right value from the MPC table and
                 * write it into the ID register.
-                */
+                */
                apic_printk(APIC_VERBOSE, KERN_INFO
                        "...changing IO-APIC physical APIC ID to %d ...",
-                       mp_ioapics[apic].mpc_apicid);
+                       mp_ioapics[apic].mp_apicid);
 
-               reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
+               reg_00.bits.ID = mp_ioapics[apic].mp_apicid;
                spin_lock_irqsave(&ioapic_lock, flags);
                io_apic_write(apic, 0, reg_00.raw);
                spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -1816,15 +1824,12 @@ static void __init setup_ioapic_ids_from_mpc(void)
                spin_lock_irqsave(&ioapic_lock, flags);
                reg_00.raw = io_apic_read(apic, 0);
                spin_unlock_irqrestore(&ioapic_lock, flags);
-               if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
+               if (reg_00.bits.ID != mp_ioapics[apic].mp_apicid)
                        printk("could not set ID!\n");
                else
                        apic_printk(APIC_VERBOSE, " ok.\n");
        }
 }
-#else
-static void __init setup_ioapic_ids_from_mpc(void) { }
-#endif
 
 int no_timer_check __initdata;
 
@@ -2015,12 +2020,12 @@ static inline void init_IO_APIC_traps(void)
  * The local APIC irq-chip implementation:
  */
 
-static void ack_apic(unsigned int irq)
+static void ack_lapic_irq(unsigned int irq)
 {
        ack_APIC_irq();
 }
 
-static void mask_lapic_irq (unsigned int irq)
+static void mask_lapic_irq(unsigned int irq)
 {
        unsigned long v;
 
@@ -2028,7 +2033,7 @@ static void mask_lapic_irq (unsigned int irq)
        apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
 }
 
-static void unmask_lapic_irq (unsigned int irq)
+static void unmask_lapic_irq(unsigned int irq)
 {
        unsigned long v;
 
@@ -2037,23 +2042,31 @@ static void unmask_lapic_irq (unsigned int irq)
 }
 
 static struct irq_chip lapic_chip __read_mostly = {
-       .name           = "local-APIC-edge",
+       .name           = "local-APIC",
        .mask           = mask_lapic_irq,
        .unmask         = unmask_lapic_irq,
-       .eoi            = ack_apic,
+       .ack            = ack_lapic_irq,
 };
 
+static void lapic_register_intr(int irq, int vector)
+{
+       irq_desc[irq].status &= ~IRQ_LEVEL;
+       set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
+                                     "edge");
+       set_intr_gate(vector, interrupt[irq]);
+}
+
 static void __init setup_nmi(void)
 {
        /*
-        * Dirty trick to enable the NMI watchdog ...
+        * Dirty trick to enable the NMI watchdog ...
         * We put the 8259A master into AEOI mode and
         * unmask on all local APICs LVT0 as NMI.
         *
         * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
         * is from Maciej W. Rozycki - so we do not have to EOI from
         * the NMI handler or the timer interrupt.
-        */ 
+        */
        apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ...");
 
        enable_NMI_through_LVT0();
@@ -2129,11 +2142,16 @@ static inline void __init unlock_ExtINT_logic(void)
 static inline void __init check_timer(void)
 {
        int apic1, pin1, apic2, pin2;
+       int no_pin1 = 0;
        int vector;
+       unsigned int ver;
        unsigned long flags;
 
        local_irq_save(flags);
 
+       ver = apic_read(APIC_LVR);
+       ver = GET_APIC_VERSION(ver);
+
        /*
         * get/set the timer IRQ vector:
         */
@@ -2142,17 +2160,17 @@ static inline void __init check_timer(void)
        set_intr_gate(vector, interrupt[0]);
 
        /*
-        * Subtle, code in do_timer_interrupt() expects an AEOI
-        * mode for the 8259A whenever interrupts are routed
-        * through I/O APICs.  Also IRQ0 has to be enabled in
-        * the 8259A which implies the virtual wire has to be
-        * disabled in the local APIC.
+        * As IRQ0 is to be enabled in the 8259A, the virtual
+        * wire has to be disabled in the local APIC.  Also
+        * timer interrupts need to be acknowledged manually in
+        * the 8259A for the i82489DX when using the NMI
+        * watchdog as that APIC treats NMIs as level-triggered.
+        * The AEOI mode will finish them in the 8259A
+        * automatically.
         */
        apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
        init_8259A(1);
-       timer_ack = 1;
-       if (timer_over_8254 > 0)
-               enable_8259A_irq(0);
+       timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
 
        pin1  = find_isa_irq_pin(0, mp_INT);
        apic1 = find_isa_irq_apic(0, mp_INT);
@@ -2162,14 +2180,33 @@ static inline void __init check_timer(void)
        printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
                vector, apic1, pin1, apic2, pin2);
 
+       /*
+        * Some BIOS writers are clueless and report the ExtINTA
+        * I/O APIC input from the cascaded 8259A as the timer
+        * interrupt input.  So just in case, if only one pin
+        * was found above, try it both directly and through the
+        * 8259A.
+        */
+       if (pin1 == -1) {
+               pin1 = pin2;
+               apic1 = apic2;
+               no_pin1 = 1;
+       } else if (pin2 == -1) {
+               pin2 = pin1;
+               apic2 = apic1;
+       }
+
        if (pin1 != -1) {
                /*
                 * Ok, does IRQ0 through the IOAPIC work?
                 */
+               if (no_pin1) {
+                       add_pin_to_irq(0, apic1, pin1);
+                       setup_timer_IRQ0_pin(apic1, pin1, vector);
+               }
                unmask_IO_APIC_irq(0);
                if (timer_irq_works()) {
                        if (nmi_watchdog == NMI_IO_APIC) {
-                               disable_8259A_irq(0);
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
@@ -2178,45 +2215,47 @@ static inline void __init check_timer(void)
                        goto out;
                }
                clear_IO_APIC_pin(apic1, pin1);
-               printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to "
-                               "IO-APIC\n");
-       }
+               if (!no_pin1)
+                       printk(KERN_ERR "..MP-BIOS bug: "
+                              "8254 timer not connected to IO-APIC\n");
 
-       printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
-       if (pin2 != -1) {
+               printk(KERN_INFO "...trying to set up timer (IRQ0) "
+                      "through the 8259A ... ");
                printk("\n..... (found pin %d) ...", pin2);
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
-               setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
+               replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
+               setup_timer_IRQ0_pin(apic2, pin2, vector);
+               unmask_IO_APIC_irq(0);
+               enable_8259A_irq(0);
                if (timer_irq_works()) {
                        printk("works.\n");
-                       if (pin1 != -1)
-                               replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
-                       else
-                               add_pin_to_irq(0, apic2, pin2);
+                       timer_through_8259 = 1;
                        if (nmi_watchdog == NMI_IO_APIC) {
+                               disable_8259A_irq(0);
                                setup_nmi();
+                               enable_8259A_irq(0);
                        }
                        goto out;
                }
                /*
                 * Cleanup, just in case ...
                 */
+               disable_8259A_irq(0);
                clear_IO_APIC_pin(apic2, pin2);
+               printk(" failed.\n");
        }
-       printk(" failed.\n");
 
        if (nmi_watchdog == NMI_IO_APIC) {
                printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
-               nmi_watchdog = 0;
+               nmi_watchdog = NMI_NONE;
        }
+       timer_ack = 0;
 
        printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
-       disable_8259A_irq(0);
-       set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq,
-                                     "fasteoi");
+       lapic_register_intr(0, vector);
        apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
@@ -2224,12 +2263,12 @@ static inline void __init check_timer(void)
                printk(" works.\n");
                goto out;
        }
+       disable_8259A_irq(0);
        apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector);
        printk(" failed.\n");
 
        printk(KERN_INFO "...trying to set up timer as ExtINT IRQ...");
 
-       timer_ack = 0;
        init_8259A(0);
        make_8259A_irq(0);
        apic_write_around(APIC_LVT0, APIC_DM_EXTINT);
@@ -2248,11 +2287,21 @@ out:
 }
 
 /*
- *
- * IRQ's that are handled by the PIC in the MPS IOAPIC case.
- * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
- *   Linux doesn't really care, as it's not actually used
- *   for any interrupt handling anyway.
+ * Traditionally ISA IRQ2 is the cascade IRQ, and is not available
+ * to devices.  However there may be an I/O APIC pin available for
+ * this interrupt regardless.  The pin may be left unconnected, but
+ * typically it will be reused as an ExtINT cascade interrupt for
+ * the master 8259A.  In the MPS case such a pin will normally be
+ * reported as an ExtINT interrupt in the MP table.  With ACPI
+ * there is no provision for ExtINT interrupts, and in the absence
+ * of an override it would be treated as an ordinary ISA I/O APIC
+ * interrupt, that is edge-triggered and unmasked by default.  We
+ * used to do this, but it caused problems on some systems because
+ * of the NMI watchdog and sometimes IRQ0 of the 8254 timer using
+ * the same ExtINT cascade interrupt to drive the local APIC of the
+ * bootstrap processor.  Therefore we refrain from routing IRQ2 to
+ * the I/O APIC in all cases now.  No actual device should request
+ * it anyway.  --macro
  */
 #define PIC_IRQS       (1 << PIC_CASCADE_IR)
 
@@ -2261,15 +2310,12 @@ void __init setup_IO_APIC(void)
        int i;
 
        /* Reserve all the system vectors. */
-       for (i = FIRST_SYSTEM_VECTOR; i < NR_VECTORS; i++)
+       for (i = first_system_vector; i < NR_VECTORS; i++)
                set_bit(i, used_vectors);
 
        enable_IO_APIC();
 
-       if (acpi_ioapic)
-               io_apic_irqs = ~0;      /* all IRQs go through IOAPIC */
-       else
-               io_apic_irqs = ~PIC_IRQS;
+       io_apic_irqs = ~PIC_IRQS;
 
        printk("ENABLING IO-APIC IRQs\n");
 
@@ -2286,28 +2332,14 @@ void __init setup_IO_APIC(void)
                print_IO_APIC();
 }
 
-static int __init setup_disable_8254_timer(char *s)
-{
-       timer_over_8254 = -1;
-       return 1;
-}
-static int __init setup_enable_8254_timer(char *s)
-{
-       timer_over_8254 = 2;
-       return 1;
-}
-
-__setup("disable_8254_timer", setup_disable_8254_timer);
-__setup("enable_8254_timer", setup_enable_8254_timer);
-
 /*
  *     Called after all the initialization is done. If we didnt find any
  *     APIC bugs then we can allow the modify fast path
  */
+
 static int __init io_apic_bug_finalize(void)
 {
-       if(sis_apic_bug == -1)
+       if (sis_apic_bug == -1)
                sis_apic_bug = 0;
        return 0;
 }
@@ -2318,17 +2350,17 @@ struct sysfs_ioapic_data {
        struct sys_device dev;
        struct IO_APIC_route_entry entry[0];
 };
-static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
+static struct sysfs_ioapic_data *mp_ioapic_data[MAX_IO_APICS];
 
 static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
 {
        struct IO_APIC_route_entry *entry;
        struct sysfs_ioapic_data *data;
        int i;
-       
+
        data = container_of(dev, struct sysfs_ioapic_data, dev);
        entry = data->entry;
-       for (i = 0; i < nr_ioapic_registers[dev->id]; i ++)
+       for (i = 0; i < nr_ioapic_registers[dev->id]; i++)
                entry[i] = ioapic_read_entry(dev->id, i);
 
        return 0;
@@ -2341,18 +2373,18 @@ static int ioapic_resume(struct sys_device *dev)
        unsigned long flags;
        union IO_APIC_reg_00 reg_00;
        int i;
-       
+
        data = container_of(dev, struct sysfs_ioapic_data, dev);
        entry = data->entry;
 
        spin_lock_irqsave(&ioapic_lock, flags);
        reg_00.raw = io_apic_read(dev->id, 0);
-       if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) {
-               reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
+       if (reg_00.bits.ID != mp_ioapics[dev->id].mp_apicid) {
+               reg_00.bits.ID = mp_ioapics[dev->id].mp_apicid;
                io_apic_write(dev->id, 0, reg_00.raw);
        }
        spin_unlock_irqrestore(&ioapic_lock, flags);
-       for (i = 0; i < nr_ioapic_registers[dev->id]; i ++)
+       for (i = 0; i < nr_ioapic_registers[dev->id]; i++)
                ioapic_write_entry(dev->id, i, entry[i]);
 
        return 0;
@@ -2366,24 +2398,23 @@ static struct sysdev_class ioapic_sysdev_class = {
 
 static int __init ioapic_init_sysfs(void)
 {
-       struct sys_device * dev;
+       struct sys_device *dev;
        int i, size, error = 0;
 
        error = sysdev_class_register(&ioapic_sysdev_class);
        if (error)
                return error;
 
-       for (i = 0; i < nr_ioapics; i++ ) {
-               size = sizeof(struct sys_device) + nr_ioapic_registers[i] 
+       for (i = 0; i < nr_ioapics; i++) {
+               size = sizeof(struct sys_device) + nr_ioapic_registers[i]
                        * sizeof(struct IO_APIC_route_entry);
-               mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL);
+               mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL);
                if (!mp_ioapic_data[i]) {
                        printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i);
                        continue;
                }
-               memset(mp_ioapic_data[i], 0, size);
                dev = &mp_ioapic_data[i]->dev;
-               dev->id = i; 
+               dev->id = i;
                dev->cls = &ioapic_sysdev_class;
                error = sysdev_register(dev);
                if (error) {
@@ -2458,7 +2489,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
                msg->address_lo =
                        MSI_ADDR_BASE_LO |
                        ((INT_DEST_MODE == 0) ?
-                               MSI_ADDR_DEST_MODE_PHYSICAL:
+MSI_ADDR_DEST_MODE_PHYSICAL:
                                MSI_ADDR_DEST_MODE_LOGICAL) |
                        ((INT_DELIVERY_MODE != dest_LowestPrio) ?
                                MSI_ADDR_REDIRECTION_CPU:
@@ -2469,7 +2500,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
                        MSI_DATA_TRIGGER_EDGE |
                        MSI_DATA_LEVEL_ASSERT |
                        ((INT_DELIVERY_MODE != dest_LowestPrio) ?
-                               MSI_DATA_DELIVERY_FIXED:
+MSI_DATA_DELIVERY_FIXED:
                                MSI_DATA_DELIVERY_LOWPRI) |
                        MSI_DATA_VECTOR(vector);
        }
@@ -2640,12 +2671,12 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 #endif /* CONFIG_HT_IRQ */
 
 /* --------------------------------------------------------------------------
-                          ACPI-based IOAPIC Configuration
+                       ACPI-based IOAPIC Configuration
    -------------------------------------------------------------------------- */
 
 #ifdef CONFIG_ACPI
 
-int __init io_apic_get_unique_id (int ioapic, int apic_id)
+int __init io_apic_get_unique_id(int ioapic, int apic_id)
 {
        union IO_APIC_reg_00 reg_00;
        static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
@@ -2654,10 +2685,10 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
        int i = 0;
 
        /*
-        * The P4 platform supports up to 256 APIC IDs on two separate APIC 
-        * buses (one for LAPICs, one for IOAPICs), where predecessors only 
+        * The P4 platform supports up to 256 APIC IDs on two separate APIC
+        * buses (one for LAPICs, one for IOAPICs), where predecessors only
         * supports up to 16 on one shared APIC bus.
-        * 
+        *
         * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
         *      advantage of new APIC bus architecture.
         */
@@ -2676,7 +2707,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
        }
 
        /*
-        * Every APIC in a system must have a unique ID or we get lots of nice 
+        * Every APIC in a system must have a unique ID or we get lots of nice
         * 'stuck on smp_invalidate_needed IPI wait' messages.
         */
        if (check_apicid_used(apic_id_map, apic_id)) {
@@ -2693,7 +2724,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
                        "trying %d\n", ioapic, apic_id, i);
 
                apic_id = i;
-       } 
+       }
 
        tmp = apicid_to_cpu_present(apic_id);
        physids_or(apic_id_map, apic_id_map, tmp);
@@ -2720,7 +2751,7 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id)
 }
 
 
-int __init io_apic_get_version (int ioapic)
+int __init io_apic_get_version(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
        unsigned long flags;
@@ -2733,7 +2764,7 @@ int __init io_apic_get_version (int ioapic)
 }
 
 
-int __init io_apic_get_redir_entries (int ioapic)
+int __init io_apic_get_redir_entries(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
        unsigned long flags;
@@ -2746,7 +2777,7 @@ int __init io_apic_get_redir_entries (int ioapic)
 }
 
 
-int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low)
+int io_apic_set_pci_routing(int ioapic, int pin, int irq, int edge_level, int active_high_low)
 {
        struct IO_APIC_route_entry entry;
 
@@ -2762,7 +2793,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
         * corresponding device driver registers for this IRQ.
         */
 
-       memset(&entry,0,sizeof(entry));
+       memset(&entry, 0, sizeof(entry));
 
        entry.delivery_mode = INT_DELIVERY_MODE;
        entry.dest_mode = INT_DEST_MODE;
@@ -2781,7 +2812,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
 
        apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry "
                "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic,
-               mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq,
+               mp_ioapics[ioapic].mp_apicid, pin, entry.vector, irq,
                edge_level, active_high_low);
 
        ioapic_register_intr(irq, entry.vector, edge_level);
@@ -2802,8 +2833,8 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
                return -1;
 
        for (i = 0; i < mp_irq_entries; i++)
-               if (mp_irqs[i].mpc_irqtype == mp_INT &&
-                   mp_irqs[i].mpc_srcbusirq == bus_irq)
+               if (mp_irqs[i].mp_irqtype == mp_INT &&
+                   mp_irqs[i].mp_srcbusirq == bus_irq)
                        break;
        if (i >= mp_irq_entries)
                return -1;
@@ -2836,3 +2867,34 @@ static int __init parse_noapic(char *arg)
        return 0;
 }
 early_param("noapic", parse_noapic);
+
+void __init ioapic_init_mappings(void)
+{
+       unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+       int i;
+
+       for (i = 0; i < nr_ioapics; i++) {
+               if (smp_found_config) {
+                       ioapic_phys = mp_ioapics[i].mp_apicaddr;
+                       if (!ioapic_phys) {
+                               printk(KERN_ERR
+                                      "WARNING: bogus zero IO-APIC "
+                                      "address found in MPTABLE, "
+                                      "disabling IO/APIC support!\n");
+                               smp_found_config = 0;
+                               skip_ioapic_setup = 1;
+                               goto fake_ioapic_page;
+                       }
+               } else {
+fake_ioapic_page:
+                       ioapic_phys = (unsigned long)
+                                     alloc_bootmem_pages(PAGE_SIZE);
+                       ioapic_phys = __pa(ioapic_phys);
+               }
+               set_fixmap_nocache(idx, ioapic_phys);
+               printk(KERN_DEBUG "mapped IOAPIC to %08lx (%08lx)\n",
+                      __fix_to_virt(idx), ioapic_phys);
+               idx++;
+       }
+}
+
index ef1a8dfcc529a36643bdbe34f835eb1819c5f265..b16ef029cf88185334c1ec93241138245d240e8b 100644 (file)
@@ -61,7 +61,7 @@ struct irq_cfg {
 };
 
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
-struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
+static struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
        [0]  = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR,  },
        [1]  = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR,  },
        [2]  = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR,  },
@@ -82,6 +82,10 @@ struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
 
 static int assign_irq_vector(int irq, cpumask_t mask);
 
+int first_system_vector = 0xfe;
+
+char system_vectors[NR_VECTORS] = { [0 ... NR_VECTORS-1] = SYS_VECTOR_FREE};
+
 #define __apicdebuginit  __init
 
 int sis_apic_bug; /* not actually supported, dummy for compile */
@@ -90,7 +94,7 @@ static int no_timer_check;
 
 static int disable_timer_pin_1 __initdata;
 
-int timer_over_8254 __initdata = 1;
+int timer_through_8259 __initdata;
 
 /* Where if anywhere is the i8259 connect in external int mode */
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
@@ -104,15 +108,17 @@ DEFINE_SPINLOCK(vector_lock);
 int nr_ioapic_registers[MAX_IO_APICS];
 
 /* I/O APIC entries */
-struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
 int nr_ioapics;
 
 /* MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
 
 /* # of MP IRQ source entries */
 int mp_irq_entries;
 
+DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
+
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
@@ -140,7 +146,7 @@ struct io_apic {
 static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
 {
        return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
-               + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK);
+               + (mp_ioapics[idx].mp_apicaddr & ~PAGE_MASK);
 }
 
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
@@ -183,7 +189,7 @@ static bool io_apic_level_ack_pending(unsigned int irq)
                        break;
                reg = io_apic_read(entry->apic, 0x10 + pin*2);
                /* Is the remote IRR bit set? */
-               if ((reg >> 14) & 1) {
+               if (reg & IO_APIC_REDIR_REMOTE_IRR) {
                        spin_unlock_irqrestore(&ioapic_lock, flags);
                        return true;
                }
@@ -298,7 +304,7 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
                        break;
                io_apic_write(apic, 0x11 + pin*2, dest);
                reg = io_apic_read(apic, 0x10 + pin*2);
-               reg &= ~0x000000ff;
+               reg &= ~IO_APIC_REDIR_VECTOR_MASK;
                reg |= vector;
                io_apic_modify(apic, reg);
                if (!entry->next)
@@ -360,16 +366,37 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
        entry->pin = pin;
 }
 
+/*
+ * Reroute an IRQ to a different pin.
+ */
+static void __init replace_pin_at_irq(unsigned int irq,
+                                     int oldapic, int oldpin,
+                                     int newapic, int newpin)
+{
+       struct irq_pin_list *entry = irq_2_pin + irq;
+
+       while (1) {
+               if (entry->apic == oldapic && entry->pin == oldpin) {
+                       entry->apic = newapic;
+                       entry->pin = newpin;
+               }
+               if (!entry->next)
+                       break;
+               entry = irq_2_pin + entry->next;
+       }
+}
+
 
 #define DO_ACTION(name,R,ACTION, FINAL)                                        \
                                                                        \
        static void name##_IO_APIC_irq (unsigned int irq)               \
        __DO_ACTION(R, ACTION, FINAL)
 
-DO_ACTION( __mask,             0, |= 0x00010000, io_apic_sync(entry->apic) )
-                                               /* mask = 1 */
-DO_ACTION( __unmask,           0, &= 0xfffeffff, )
-                                               /* mask = 0 */
+/* mask = 1 */
+DO_ACTION(__mask,      0, |= IO_APIC_REDIR_MASKED, io_apic_sync(entry->apic))
+
+/* mask = 0 */
+DO_ACTION(__unmask,    0, &= ~IO_APIC_REDIR_MASKED, )
 
 static void mask_IO_APIC_irq (unsigned int irq)
 {
@@ -430,20 +457,6 @@ static int __init disable_timer_pin_setup(char *arg)
 }
 __setup("disable_timer_pin_1", disable_timer_pin_setup);
 
-static int __init setup_disable_8254_timer(char *s)
-{
-       timer_over_8254 = -1;
-       return 1;
-}
-static int __init setup_enable_8254_timer(char *s)
-{
-       timer_over_8254 = 2;
-       return 1;
-}
-
-__setup("disable_8254_timer", setup_disable_8254_timer);
-__setup("enable_8254_timer", setup_enable_8254_timer);
-
 
 /*
  * Find the IRQ entry number of a certain pin.
@@ -453,10 +466,10 @@ static int find_irq_entry(int apic, int pin, int type)
        int i;
 
        for (i = 0; i < mp_irq_entries; i++)
-               if (mp_irqs[i].mpc_irqtype == type &&
-                   (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
-                    mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
-                   mp_irqs[i].mpc_dstirq == pin)
+               if (mp_irqs[i].mp_irqtype == type &&
+                   (mp_irqs[i].mp_dstapic == mp_ioapics[apic].mp_apicid ||
+                    mp_irqs[i].mp_dstapic == MP_APIC_ALL) &&
+                   mp_irqs[i].mp_dstirq == pin)
                        return i;
 
        return -1;
@@ -470,13 +483,13 @@ static int __init find_isa_irq_pin(int irq, int type)
        int i;
 
        for (i = 0; i < mp_irq_entries; i++) {
-               int lbus = mp_irqs[i].mpc_srcbus;
+               int lbus = mp_irqs[i].mp_srcbus;
 
                if (test_bit(lbus, mp_bus_not_pci) &&
-                   (mp_irqs[i].mpc_irqtype == type) &&
-                   (mp_irqs[i].mpc_srcbusirq == irq))
+                   (mp_irqs[i].mp_irqtype == type) &&
+                   (mp_irqs[i].mp_srcbusirq == irq))
 
-                       return mp_irqs[i].mpc_dstirq;
+                       return mp_irqs[i].mp_dstirq;
        }
        return -1;
 }
@@ -486,17 +499,17 @@ static int __init find_isa_irq_apic(int irq, int type)
        int i;
 
        for (i = 0; i < mp_irq_entries; i++) {
-               int lbus = mp_irqs[i].mpc_srcbus;
+               int lbus = mp_irqs[i].mp_srcbus;
 
                if (test_bit(lbus, mp_bus_not_pci) &&
-                   (mp_irqs[i].mpc_irqtype == type) &&
-                   (mp_irqs[i].mpc_srcbusirq == irq))
+                   (mp_irqs[i].mp_irqtype == type) &&
+                   (mp_irqs[i].mp_srcbusirq == irq))
                        break;
        }
        if (i < mp_irq_entries) {
                int apic;
                for(apic = 0; apic < nr_ioapics; apic++) {
-                       if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+                       if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic)
                                return apic;
                }
        }
@@ -516,28 +529,28 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
 
        apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
                bus, slot, pin);
-       if (mp_bus_id_to_pci_bus[bus] == -1) {
+       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].mpc_srcbus;
+               int lbus = mp_irqs[i].mp_srcbus;
 
                for (apic = 0; apic < nr_ioapics; apic++)
-                       if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic ||
-                           mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
+                       if (mp_ioapics[apic].mp_apicid == mp_irqs[i].mp_dstapic ||
+                           mp_irqs[i].mp_dstapic == MP_APIC_ALL)
                                break;
 
                if (!test_bit(lbus, mp_bus_not_pci) &&
-                   !mp_irqs[i].mpc_irqtype &&
+                   !mp_irqs[i].mp_irqtype &&
                    (bus == lbus) &&
-                   (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) {
-                       int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
+                   (slot == ((mp_irqs[i].mp_srcbusirq >> 2) & 0x1f))) {
+                       int irq = pin_2_irq(i,apic,mp_irqs[i].mp_dstirq);
 
                        if (!(apic || IO_APIC_IRQ(irq)))
                                continue;
 
-                       if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
+                       if (pin == (mp_irqs[i].mp_srcbusirq & 3))
                                return irq;
                        /*
                         * Use the first all-but-pin matching entry as a
@@ -565,13 +578,13 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
 
 static int MPBIOS_polarity(int idx)
 {
-       int bus = mp_irqs[idx].mpc_srcbus;
+       int bus = mp_irqs[idx].mp_srcbus;
        int polarity;
 
        /*
         * Determine IRQ line polarity (high active or low active):
         */
-       switch (mp_irqs[idx].mpc_irqflag & 3)
+       switch (mp_irqs[idx].mp_irqflag & 3)
        {
                case 0: /* conforms, ie. bus-type dependent polarity */
                        if (test_bit(bus, mp_bus_not_pci))
@@ -607,13 +620,13 @@ static int MPBIOS_polarity(int idx)
 
 static int MPBIOS_trigger(int idx)
 {
-       int bus = mp_irqs[idx].mpc_srcbus;
+       int bus = mp_irqs[idx].mp_srcbus;
        int trigger;
 
        /*
         * Determine IRQ trigger mode (edge or level sensitive):
         */
-       switch ((mp_irqs[idx].mpc_irqflag>>2) & 3)
+       switch ((mp_irqs[idx].mp_irqflag>>2) & 3)
        {
                case 0: /* conforms, ie. bus-type dependent */
                        if (test_bit(bus, mp_bus_not_pci))
@@ -660,16 +673,16 @@ static inline int irq_trigger(int idx)
 static int pin_2_irq(int idx, int apic, int pin)
 {
        int irq, i;
-       int bus = mp_irqs[idx].mpc_srcbus;
+       int bus = mp_irqs[idx].mp_srcbus;
 
        /*
         * Debugging check, we are in big trouble if this message pops up!
         */
-       if (mp_irqs[idx].mpc_dstirq != pin)
+       if (mp_irqs[idx].mp_dstirq != pin)
                printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
 
        if (test_bit(bus, mp_bus_not_pci)) {
-               irq = mp_irqs[idx].mpc_srcbusirq;
+               irq = mp_irqs[idx].mp_srcbusirq;
        } else {
                /*
                 * PCI IRQs are mapped in order
@@ -730,7 +743,7 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
                offset = current_offset;
 next:
                vector += 8;
-               if (vector >= FIRST_SYSTEM_VECTOR) {
+               if (vector >= first_system_vector) {
                        /* If we run out of vectors on large boxen, must share them. */
                        offset = (offset + 1) % 8;
                        vector = FIRST_DEVICE_VECTOR + offset;
@@ -788,7 +801,7 @@ static void __clear_irq_vector(int irq)
        cpus_clear(cfg->domain);
 }
 
-void __setup_vector_irq(int cpu)
+static void __setup_vector_irq(int cpu)
 {
        /* Initialize vector_irq on a new cpu */
        /* This function must be called with vector_lock held */
@@ -811,6 +824,13 @@ void __setup_vector_irq(int cpu)
        }
 }
 
+void setup_vector_irq(int cpu)
+{
+       spin_lock(&vector_lock);
+       __setup_vector_irq(smp_processor_id());
+       spin_unlock(&vector_lock);
+}
+
 
 static struct irq_chip ioapic_chip;
 
@@ -846,7 +866,7 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
        apic_printk(APIC_VERBOSE,KERN_DEBUG
                    "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
                    "IRQ %d Mode:%i Active:%i)\n",
-                   apic, mp_ioapics[apic].mpc_apicid, pin, cfg->vector,
+                   apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector,
                    irq, trigger, polarity);
 
        /*
@@ -887,10 +907,10 @@ static void __init setup_IO_APIC_irqs(void)
                idx = find_irq_entry(apic,pin,mp_INT);
                if (idx == -1) {
                        if (first_notcon) {
-                               apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
+                               apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mp_apicid, pin);
                                first_notcon = 0;
                        } else
-                               apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin);
+                               apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mp_apicid, pin);
                        continue;
                }
                if (!first_notcon) {
@@ -911,26 +931,21 @@ static void __init setup_IO_APIC_irqs(void)
 }
 
 /*
- * Set up the 8259A-master output pin as broadcast to all
- * CPUs.
+ * Set up the timer pin, possibly with the 8259A-master behind.
  */
-static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
+static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
+                                       int vector)
 {
        struct IO_APIC_route_entry entry;
 
        memset(&entry, 0, sizeof(entry));
 
-       disable_8259A_irq(0);
-
-       /* mask LVT0 */
-       apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
-
        /*
         * We use logical delivery to get the timer IRQ
         * to the first CPU.
         */
        entry.dest_mode = INT_DEST_MODE;
-       entry.mask = 0;                                 /* unmask IRQ now */
+       entry.mask = 1;                                 /* mask IRQ now */
        entry.dest = cpu_mask_to_apicid(TARGET_CPUS);
        entry.delivery_mode = INT_DELIVERY_MODE;
        entry.polarity = 0;
@@ -939,7 +954,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
 
        /*
         * The timer IRQ doesn't have to know that behind the
-        * scene we have a 8259A-master in AEOI mode ...
+        * scene we may have a 8259A-master in AEOI mode ...
         */
        set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
 
@@ -947,8 +962,6 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * Add it to the IO-APIC irq-routing table:
         */
        ioapic_write_entry(apic, pin, entry);
-
-       enable_8259A_irq(0);
 }
 
 void __apicdebuginit print_IO_APIC(void)
@@ -965,7 +978,7 @@ void __apicdebuginit print_IO_APIC(void)
        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
        for (i = 0; i < nr_ioapics; i++)
                printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
-                      mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
+                      mp_ioapics[i].mp_apicid, nr_ioapic_registers[i]);
 
        /*
         * We are a bit conservative about what we expect.  We have to
@@ -983,7 +996,7 @@ void __apicdebuginit print_IO_APIC(void)
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
        printk("\n");
-       printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
+       printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mp_apicid);
        printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
        printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
 
@@ -1077,6 +1090,7 @@ void __apicdebuginit print_local_APIC(void * dummy)
 
        printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
                smp_processor_id(), hard_smp_processor_id());
+       v = apic_read(APIC_ID);
        printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(read_apic_id()));
        v = apic_read(APIC_LVR);
        printk(KERN_INFO "... APIC VERSION: %08x\n", v);
@@ -1540,7 +1554,7 @@ static inline void init_IO_APIC_traps(void)
        }
 }
 
-static void enable_lapic_irq (unsigned int irq)
+static void unmask_lapic_irq(unsigned int irq)
 {
        unsigned long v;
 
@@ -1548,7 +1562,7 @@ static void enable_lapic_irq (unsigned int irq)
        apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
 }
 
-static void disable_lapic_irq (unsigned int irq)
+static void mask_lapic_irq(unsigned int irq)
 {
        unsigned long v;
 
@@ -1561,19 +1575,20 @@ static void ack_lapic_irq (unsigned int irq)
        ack_APIC_irq();
 }
 
-static void end_lapic_irq (unsigned int i) { /* nothing */ }
-
-static struct hw_interrupt_type lapic_irq_type __read_mostly = {
-       .name = "local-APIC",
-       .typename = "local-APIC-edge",
-       .startup = NULL, /* startup_irq() not used for IRQ0 */
-       .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
-       .enable = enable_lapic_irq,
-       .disable = disable_lapic_irq,
-       .ack = ack_lapic_irq,
-       .end = end_lapic_irq,
+static struct irq_chip lapic_chip __read_mostly = {
+       .name           = "local-APIC",
+       .mask           = mask_lapic_irq,
+       .unmask         = unmask_lapic_irq,
+       .ack            = ack_lapic_irq,
 };
 
+static void lapic_register_intr(int irq)
+{
+       irq_desc[irq].status &= ~IRQ_LEVEL;
+       set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
+                                     "edge");
+}
+
 static void __init setup_nmi(void)
 {
        /*
@@ -1659,6 +1674,7 @@ static inline void __init check_timer(void)
        struct irq_cfg *cfg = irq_cfg + 0;
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
+       int no_pin1 = 0;
 
        local_irq_save(flags);
 
@@ -1669,16 +1685,11 @@ static inline void __init check_timer(void)
        assign_irq_vector(0, TARGET_CPUS);
 
        /*
-        * Subtle, code in do_timer_interrupt() expects an AEOI
-        * mode for the 8259A whenever interrupts are routed
-        * through I/O APICs.  Also IRQ0 has to be enabled in
-        * the 8259A which implies the virtual wire has to be
-        * disabled in the local APIC.
+        * As IRQ0 is to be enabled in the 8259A, the virtual
+        * wire has to be disabled in the local APIC.
         */
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
        init_8259A(1);
-       if (timer_over_8254 > 0)
-               enable_8259A_irq(0);
 
        pin1  = find_isa_irq_pin(0, mp_INT);
        apic1 = find_isa_irq_apic(0, mp_INT);
@@ -1688,15 +1699,33 @@ static inline void __init check_timer(void)
        apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
                cfg->vector, apic1, pin1, apic2, pin2);
 
+       /*
+        * Some BIOS writers are clueless and report the ExtINTA
+        * I/O APIC input from the cascaded 8259A as the timer
+        * interrupt input.  So just in case, if only one pin
+        * was found above, try it both directly and through the
+        * 8259A.
+        */
+       if (pin1 == -1) {
+               pin1 = pin2;
+               apic1 = apic2;
+               no_pin1 = 1;
+       } else if (pin2 == -1) {
+               pin2 = pin1;
+               apic2 = apic1;
+       }
+
        if (pin1 != -1) {
                /*
                 * Ok, does IRQ0 through the IOAPIC work?
                 */
+               if (no_pin1) {
+                       add_pin_to_irq(0, apic1, pin1);
+                       setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
+               }
                unmask_IO_APIC_irq(0);
                if (!no_timer_check && timer_irq_works()) {
-                       nmi_watchdog_default();
                        if (nmi_watchdog == NMI_IO_APIC) {
-                               disable_8259A_irq(0);
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
@@ -1705,43 +1734,48 @@ static inline void __init check_timer(void)
                        goto out;
                }
                clear_IO_APIC_pin(apic1, pin1);
-               apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not "
-                               "connected to IO-APIC\n");
-       }
+               if (!no_pin1)
+                       apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: "
+                                   "8254 timer not connected to IO-APIC\n");
 
-       apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) "
-                               "through the 8259A ... ");
-       if (pin2 != -1) {
+               apic_printk(APIC_VERBOSE,KERN_INFO
+                       "...trying to set up timer (IRQ0) "
+                       "through the 8259A ... ");
                apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
                        apic2, pin2);
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
-               setup_ExtINT_IRQ0_pin(apic2, pin2, cfg->vector);
+               replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
+               setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
+               unmask_IO_APIC_irq(0);
+               enable_8259A_irq(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_VERBOSE," works.\n");
-                       nmi_watchdog_default();
+                       timer_through_8259 = 1;
                        if (nmi_watchdog == NMI_IO_APIC) {
+                               disable_8259A_irq(0);
                                setup_nmi();
+                               enable_8259A_irq(0);
                        }
                        goto out;
                }
                /*
                 * Cleanup, just in case ...
                 */
+               disable_8259A_irq(0);
                clear_IO_APIC_pin(apic2, pin2);
+               apic_printk(APIC_VERBOSE," failed.\n");
        }
-       apic_printk(APIC_VERBOSE," failed.\n");
 
        if (nmi_watchdog == NMI_IO_APIC) {
                printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
-               nmi_watchdog = 0;
+               nmi_watchdog = NMI_NONE;
        }
 
        apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
-       disable_8259A_irq(0);
-       irq_desc[0].chip = &lapic_irq_type;
+       lapic_register_intr(0);
        apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector);     /* Fixed mode */
        enable_8259A_irq(0);
 
@@ -1749,6 +1783,7 @@ static inline void __init check_timer(void)
                apic_printk(APIC_VERBOSE," works.\n");
                goto out;
        }
+       disable_8259A_irq(0);
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
        apic_printk(APIC_VERBOSE," failed.\n");
 
@@ -1778,11 +1813,21 @@ static int __init notimercheck(char *s)
 __setup("no_timer_check", notimercheck);
 
 /*
- *
- * IRQs that are handled by the PIC in the MPS IOAPIC case.
- * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
- *   Linux doesn't really care, as it's not actually used
- *   for any interrupt handling anyway.
+ * Traditionally ISA IRQ2 is the cascade IRQ, and is not available
+ * to devices.  However there may be an I/O APIC pin available for
+ * this interrupt regardless.  The pin may be left unconnected, but
+ * typically it will be reused as an ExtINT cascade interrupt for
+ * the master 8259A.  In the MPS case such a pin will normally be
+ * reported as an ExtINT interrupt in the MP table.  With ACPI
+ * there is no provision for ExtINT interrupts, and in the absence
+ * of an override it would be treated as an ordinary ISA I/O APIC
+ * interrupt, that is edge-triggered and unmasked by default.  We
+ * used to do this, but it caused problems on some systems because
+ * of the NMI watchdog and sometimes IRQ0 of the 8254 timer using
+ * the same ExtINT cascade interrupt to drive the local APIC of the
+ * bootstrap processor.  Therefore we refrain from routing IRQ2 to
+ * the I/O APIC in all cases now.  No actual device should request
+ * it anyway.  --macro
  */
 #define PIC_IRQS       (1<<2)
 
@@ -1793,10 +1838,7 @@ void __init setup_IO_APIC(void)
         * calling enable_IO_APIC() is moved to setup_local_APIC for BP
         */
 
-       if (acpi_ioapic)
-               io_apic_irqs = ~0;      /* all IRQs go through IOAPIC */
-       else
-               io_apic_irqs = ~PIC_IRQS;
+       io_apic_irqs = ~PIC_IRQS;
 
        apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
 
@@ -1841,8 +1883,8 @@ static int ioapic_resume(struct sys_device *dev)
 
        spin_lock_irqsave(&ioapic_lock, flags);
        reg_00.raw = io_apic_read(dev->id, 0);
-       if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) {
-               reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
+       if (reg_00.bits.ID != mp_ioapics[dev->id].mp_apicid) {
+               reg_00.bits.ID = mp_ioapics[dev->id].mp_apicid;
                io_apic_write(dev->id, 0, reg_00.raw);
        }
        spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -2242,8 +2284,8 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
                return -1;
 
        for (i = 0; i < mp_irq_entries; i++)
-               if (mp_irqs[i].mpc_irqtype == mp_INT &&
-                   mp_irqs[i].mpc_srcbusirq == bus_irq)
+               if (mp_irqs[i].mp_irqtype == mp_INT &&
+                   mp_irqs[i].mp_srcbusirq == bus_irq)
                        break;
        if (i >= mp_irq_entries)
                return -1;
@@ -2336,7 +2378,7 @@ void __init ioapic_init_mappings(void)
        ioapic_res = ioapic_setup_resources();
        for (i = 0; i < nr_ioapics; i++) {
                if (smp_found_config) {
-                       ioapic_phys = mp_ioapics[i].mpc_apicaddr;
+                       ioapic_phys = mp_ioapics[i].mp_apicaddr;
                } else {
                        ioapic_phys = (unsigned long)
                                alloc_bootmem_pages(PAGE_SIZE);
index c0df7b89ca230d83e2f3b0f65dfd900a813d69e8..9d98cda39ad9ea006729b999daec04c0e1e32d72 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
-#include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
 
index 147352df28b9c74146a102f6c8b22b17e2b11d6d..47a6f6f124789a32179172920e4f6a436700ec50 100644 (file)
@@ -48,6 +48,29 @@ void ack_bad_irq(unsigned int irq)
 #endif
 }
 
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+/* Debugging check for stack overflow: is there less than 1KB free? */
+static int check_stack_overflow(void)
+{
+       long sp;
+
+       __asm__ __volatile__("andl %%esp,%0" :
+                            "=r" (sp) : "0" (THREAD_SIZE - 1));
+
+       return sp < (sizeof(struct thread_info) + STACK_WARN);
+}
+
+static void print_stack_overflow(void)
+{
+       printk(KERN_WARNING "low stack detected by irq handler\n");
+       dump_stack();
+}
+
+#else
+static inline int check_stack_overflow(void) { return 0; }
+static inline void print_stack_overflow(void) { }
+#endif
+
 #ifdef CONFIG_4KSTACKS
 /*
  * per-CPU IRQ handling contexts (thread information and stack)
@@ -59,48 +82,29 @@ union irq_ctx {
 
 static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
 static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
-#endif
 
-/*
- * do_IRQ handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- */
-unsigned int do_IRQ(struct pt_regs *regs)
-{      
-       struct pt_regs *old_regs;
-       /* high bit used in ret_from_ code */
-       int irq = ~regs->orig_ax;
-       struct irq_desc *desc = irq_desc + irq;
-#ifdef CONFIG_4KSTACKS
-       union irq_ctx *curctx, *irqctx;
-       u32 *isp;
-#endif
+static char softirq_stack[NR_CPUS * THREAD_SIZE]
+               __attribute__((__section__(".bss.page_aligned")));
 
-       if (unlikely((unsigned)irq >= NR_IRQS)) {
-               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
-                                       __func__, irq);
-               BUG();
-       }
+static char hardirq_stack[NR_CPUS * THREAD_SIZE]
+               __attribute__((__section__(".bss.page_aligned")));
 
-       old_regs = set_irq_regs(regs);
-       irq_enter();
-#ifdef CONFIG_DEBUG_STACKOVERFLOW
-       /* Debugging check for stack overflow: is there less than 1KB free? */
-       {
-               long sp;
-
-               __asm__ __volatile__("andl %%esp,%0" :
-                                       "=r" (sp) : "0" (THREAD_SIZE - 1));
-               if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
-                       printk("do_IRQ: stack overflow: %ld\n",
-                               sp - sizeof(struct thread_info));
-                       dump_stack();
-               }
-       }
-#endif
+static void call_on_stack(void *func, void *stack)
+{
+       asm volatile("xchgl     %%ebx,%%esp     \n"
+                    "call      *%%edi          \n"
+                    "movl      %%ebx,%%esp     \n"
+                    : "=b" (stack)
+                    : "0" (stack),
+                      "D"(func)
+                    : "memory", "cc", "edx", "ecx", "eax");
+}
 
-#ifdef CONFIG_4KSTACKS
+static inline int
+execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
+{
+       union irq_ctx *curctx, *irqctx;
+       u32 *isp, arg1, arg2;
 
        curctx = (union irq_ctx *) current_thread_info();
        irqctx = hardirq_ctx[smp_processor_id()];
@@ -111,52 +115,39 @@ unsigned int do_IRQ(struct pt_regs *regs)
         * handler) we can't do that and just have to keep using the
         * current stack (which is the irq stack already after all)
         */
-       if (curctx != irqctx) {
-               int arg1, arg2, bx;
-
-               /* build the stack frame on the IRQ stack */
-               isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
-               irqctx->tinfo.task = curctx->tinfo.task;
-               irqctx->tinfo.previous_esp = current_stack_pointer;
+       if (unlikely(curctx == irqctx))
+               return 0;
 
-               /*
-                * Copy the softirq bits in preempt_count so that the
-                * softirq checks work in the hardirq context.
-                */
-               irqctx->tinfo.preempt_count =
-                       (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
-                       (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
-
-               asm volatile(
-                       "       xchgl  %%ebx,%%esp    \n"
-                       "       call   *%%edi         \n"
-                       "       movl   %%ebx,%%esp    \n"
-                       : "=a" (arg1), "=d" (arg2), "=b" (bx)
-                       :  "0" (irq),   "1" (desc),  "2" (isp),
-                          "D" (desc->handle_irq)
-                       : "memory", "cc", "ecx"
-               );
-       } else
-#endif
-               desc->handle_irq(irq, desc);
+       /* build the stack frame on the IRQ stack */
+       isp = (u32 *) ((char*)irqctx + sizeof(*irqctx));
+       irqctx->tinfo.task = curctx->tinfo.task;
+       irqctx->tinfo.previous_esp = current_stack_pointer;
 
-       irq_exit();
-       set_irq_regs(old_regs);
+       /*
+        * Copy the softirq bits in preempt_count so that the
+        * softirq checks work in the hardirq context.
+        */
+       irqctx->tinfo.preempt_count =
+               (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
+               (curctx->tinfo.preempt_count & SOFTIRQ_MASK);
+
+       if (unlikely(overflow))
+               call_on_stack(print_stack_overflow, isp);
+
+       asm volatile("xchgl     %%ebx,%%esp     \n"
+                    "call      *%%edi          \n"
+                    "movl      %%ebx,%%esp     \n"
+                    : "=a" (arg1), "=d" (arg2), "=b" (isp)
+                    :  "0" (irq),   "1" (desc),  "2" (isp),
+                       "D" (desc->handle_irq)
+                    : "memory", "cc", "ecx");
        return 1;
 }
 
-#ifdef CONFIG_4KSTACKS
-
-static char softirq_stack[NR_CPUS * THREAD_SIZE]
-               __attribute__((__section__(".bss.page_aligned")));
-
-static char hardirq_stack[NR_CPUS * THREAD_SIZE]
-               __attribute__((__section__(".bss.page_aligned")));
-
 /*
  * allocate per-cpu stacks for hardirq and for softirq processing
  */
-void irq_ctx_init(int cpu)
+void __cpuinit irq_ctx_init(int cpu)
 {
        union irq_ctx *irqctx;
 
@@ -164,25 +155,25 @@ void irq_ctx_init(int cpu)
                return;
 
        irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
-       irqctx->tinfo.task              = NULL;
-       irqctx->tinfo.exec_domain       = NULL;
-       irqctx->tinfo.cpu               = cpu;
-       irqctx->tinfo.preempt_count     = HARDIRQ_OFFSET;
-       irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
+       irqctx->tinfo.task              = NULL;
+       irqctx->tinfo.exec_domain       = NULL;
+       irqctx->tinfo.cpu               = cpu;
+       irqctx->tinfo.preempt_count     = HARDIRQ_OFFSET;
+       irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
 
        hardirq_ctx[cpu] = irqctx;
 
        irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
-       irqctx->tinfo.task              = NULL;
-       irqctx->tinfo.exec_domain       = NULL;
-       irqctx->tinfo.cpu               = cpu;
-       irqctx->tinfo.preempt_count     = 0;
-       irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
+       irqctx->tinfo.task              = NULL;
+       irqctx->tinfo.exec_domain       = NULL;
+       irqctx->tinfo.cpu               = cpu;
+       irqctx->tinfo.preempt_count     = 0;
+       irqctx->tinfo.addr_limit        = MAKE_MM_SEG(0);
 
        softirq_ctx[cpu] = irqctx;
 
-       printk("CPU %u irqstacks, hard=%p soft=%p\n",
-               cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
+       printk(KERN_DEBUG "CPU %u irqstacks, hard=%p soft=%p\n",
+              cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
 }
 
 void irq_ctx_exit(int cpu)
@@ -211,24 +202,55 @@ asmlinkage void do_softirq(void)
                /* build the stack frame on the softirq stack */
                isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
 
-               asm volatile(
-                       "       xchgl   %%ebx,%%esp     \n"
-                       "       call    __do_softirq    \n"
-                       "       movl    %%ebx,%%esp     \n"
-                       : "=b"(isp)
-                       : "0"(isp)
-                       : "memory", "cc", "edx", "ecx", "eax"
-               );
+               call_on_stack(__do_softirq, isp);
                /*
                 * Shouldnt happen, we returned above if in_interrupt():
-                */
+                */
                WARN_ON_ONCE(softirq_count());
        }
 
        local_irq_restore(flags);
 }
+
+#else
+static inline int
+execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) { return 0; }
 #endif
 
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+unsigned int do_IRQ(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs;
+       /* high bit used in ret_from_ code */
+       int overflow, irq = ~regs->orig_ax;
+       struct irq_desc *desc = irq_desc + irq;
+
+       if (unlikely((unsigned)irq >= NR_IRQS)) {
+               printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
+                                       __func__, irq);
+               BUG();
+       }
+
+       old_regs = set_irq_regs(regs);
+       irq_enter();
+
+       overflow = check_stack_overflow();
+
+       if (!execute_on_irq_stack(overflow, desc, irq)) {
+               if (unlikely(overflow))
+                       print_stack_overflow();
+               desc->handle_irq(irq, desc);
+       }
+
+       irq_exit();
+       set_irq_regs(old_regs);
+       return 1;
+}
+
 /*
  * Interrupt statistics:
  */
@@ -313,16 +335,20 @@ skip:
                                per_cpu(irq_stat,j).irq_tlb_count);
                seq_printf(p, "  TLB shootdowns\n");
 #endif
+#ifdef CONFIG_X86_MCE
                seq_printf(p, "TRM: ");
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ",
                                per_cpu(irq_stat,j).irq_thermal_count);
                seq_printf(p, "  Thermal event interrupts\n");
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
                seq_printf(p, "SPU: ");
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ",
                                per_cpu(irq_stat,j).irq_spurious_count);
                seq_printf(p, "  Spurious interrupts\n");
+#endif
                seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
 #if defined(CONFIG_X86_IO_APIC)
                seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
@@ -331,6 +357,40 @@ skip:
        return 0;
 }
 
+/*
+ * /proc/stat helpers
+ */
+u64 arch_irq_stat_cpu(unsigned int cpu)
+{
+       u64 sum = nmi_count(cpu);
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       sum += per_cpu(irq_stat, cpu).apic_timer_irqs;
+#endif
+#ifdef CONFIG_SMP
+       sum += per_cpu(irq_stat, cpu).irq_resched_count;
+       sum += per_cpu(irq_stat, cpu).irq_call_count;
+       sum += per_cpu(irq_stat, cpu).irq_tlb_count;
+#endif
+#ifdef CONFIG_X86_MCE
+       sum += per_cpu(irq_stat, cpu).irq_thermal_count;
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
+       sum += per_cpu(irq_stat, cpu).irq_spurious_count;
+#endif
+       return sum;
+}
+
+u64 arch_irq_stat(void)
+{
+       u64 sum = atomic_read(&irq_err_count);
+
+#ifdef CONFIG_X86_IO_APIC
+       sum += atomic_read(&irq_mis_count);
+#endif
+       return sum;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 #include <mach_apic.h>
 
index 3aac15466a91f951df85fdcaccdc7e0dd2196d8b..1f78b238d8d2cc8778520e048fe69d36a97209b2 100644 (file)
@@ -135,6 +135,7 @@ skip:
                        seq_printf(p, "%10u ", cpu_pda(j)->irq_tlb_count);
                seq_printf(p, "  TLB shootdowns\n");
 #endif
+#ifdef CONFIG_X86_MCE
                seq_printf(p, "TRM: ");
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", cpu_pda(j)->irq_thermal_count);
@@ -143,6 +144,7 @@ skip:
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", cpu_pda(j)->irq_threshold_count);
                seq_printf(p, "  Threshold APIC interrupts\n");
+#endif
                seq_printf(p, "SPU: ");
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", cpu_pda(j)->irq_spurious_count);
@@ -152,6 +154,32 @@ skip:
        return 0;
 }
 
+/*
+ * /proc/stat helpers
+ */
+u64 arch_irq_stat_cpu(unsigned int cpu)
+{
+       u64 sum = cpu_pda(cpu)->__nmi_count;
+
+       sum += cpu_pda(cpu)->apic_timer_irqs;
+#ifdef CONFIG_SMP
+       sum += cpu_pda(cpu)->irq_resched_count;
+       sum += cpu_pda(cpu)->irq_call_count;
+       sum += cpu_pda(cpu)->irq_tlb_count;
+#endif
+#ifdef CONFIG_X86_MCE
+       sum += cpu_pda(cpu)->irq_thermal_count;
+       sum += cpu_pda(cpu)->irq_threshold_count;
+#endif
+       sum += cpu_pda(cpu)->irq_spurious_count;
+       return sum;
+}
+
+u64 arch_irq_stat(void)
+{
+       return atomic_read(&irq_err_count);
+}
+
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
diff --git a/arch/x86/kernel/irqinit_32.c b/arch/x86/kernel/irqinit_32.c
new file mode 100644 (file)
index 0000000..d669142
--- /dev/null
@@ -0,0 +1,114 @@
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.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 <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/timer.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+#include <asm/apic.h>
+#include <asm/arch_hooks.h>
+#include <asm/i8259.h>
+
+
+
+/*
+ * 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
+ * (ie as explained in the intel literature). On a 386, you
+ * can't use exception 16 due to bad IBM design, so we have to
+ * rely on the less exact irq13.
+ *
+ * Careful.. Not only is IRQ13 unreliable, but it is also
+ * leads to races. IBM designers who came up with it should
+ * be shot.
+ */
+
+static irqreturn_t math_error_irq(int cpl, void *dev_id)
+{
+       extern void math_error(void __user *);
+       outb(0,0xF0);
+       if (ignore_fpu_irq || !boot_cpu_data.hard_math)
+               return IRQ_NONE;
+       math_error((void __user *)get_irq_regs()->ip);
+       return IRQ_HANDLED;
+}
+
+/*
+ * New motherboards sometimes make IRQ 13 be a PCI interrupt,
+ * so allow interrupt sharing.
+ */
+static struct irqaction fpu_irq = {
+       .handler = math_error_irq,
+       .mask = CPU_MASK_NONE,
+       .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 < 16; i++) {
+               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")));
+
+void __init native_init_IRQ(void)
+{
+       int i;
+
+       /* all the set up before the call gates are initialised */
+       pre_intr_init_hook();
+
+       /*
+        * 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 (i >= NR_IRQS)
+                       break;
+               /* SYSCALL_VECTOR was reserved in trap_init. */
+               if (!test_bit(vector, used_vectors))
+                       set_intr_gate(vector, interrupt[i]);
+       }
+
+       /* setup after call gates are initialised (usually add in
+        * the architecture specific gates)
+        */
+       intr_init_hook();
+
+       /*
+        * External FPU? Set up irq13 if so, for
+        * original braindamaged IBM FERR coupling.
+        */
+       if (boot_cpu_data.hard_math && !cpu_has_fpu)
+               setup_irq(FPU_IRQ, &fpu_irq);
+
+       irq_ctx_init(smp_processor_id());
+}
diff --git a/arch/x86/kernel/irqinit_64.c b/arch/x86/kernel/irqinit_64.c
new file mode 100644 (file)
index 0000000..31f49e8
--- /dev/null
@@ -0,0 +1,217 @@
+#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 <asm/acpi.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+#include <asm/apic.h>
+#include <asm/i8259.h>
+
+/*
+ * Common place to define all x86 IRQ vectors
+ *
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ *
+ * These macros create the low-level assembly IRQ routines that save
+ * register context and call do_IRQ(). do_IRQ() then does all the
+ * operations that are needed to keep the AT (or SMP IOAPIC)
+ * interrupt-controller happy.
+ */
+
+#define IRQ_NAME2(nr) nr##_interrupt(void)
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+
+/*
+ *     SMP has a few special interrupts for IPI messages
+ */
+
+#define BUILD_IRQ(nr)                          \
+       asmlinkage void IRQ_NAME(nr);           \
+       asm("\n.p2align\n"                      \
+           "IRQ" #nr "_interrupt:\n\t"         \
+           "push $~(" #nr ") ; "               \
+           "jmp common_interrupt");
+
+#define BI(x,y) \
+       BUILD_IRQ(x##y)
+
+#define BUILD_16_IRQS(x) \
+       BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+       BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+       BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+       BI(x,c) BI(x,d) BI(x,e) BI(x,f)
+
+/*
+ * 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)
+ */
+                                     BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
+BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
+
+#undef BUILD_16_IRQS
+#undef BI
+
+
+#define IRQ(x,y) \
+       IRQ##x##y##_interrupt
+
+#define IRQLIST_16(x) \
+       IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+       IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+       IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+       IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
+
+/* for the irq vectors */
+static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = {
+                                         IRQLIST_16(0x2), IRQLIST_16(0x3),
+       IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
+       IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
+       IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
+};
+
+#undef IRQ
+#undef IRQLIST_16
+
+
+
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+
+static struct irqaction irq2 = {
+       .handler = no_action,
+       .mask = CPU_MASK_NONE,
+       .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
+};
+
+static void __init init_ISA_irqs (void)
+{
+       int i;
+
+       init_bsp_APIC();
+       init_8259A(0);
+
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc[i].status = IRQ_DISABLED;
+               irq_desc[i].action = NULL;
+               irq_desc[i].depth = 1;
+
+               if (i < 16) {
+                       /*
+                        * 16 old-style INTA-cycle interrupts:
+                        */
+                       set_irq_chip_and_handler_name(i, &i8259A_chip,
+                                                     handle_level_irq, "XT");
+               } else {
+                       /*
+                        * 'high' PCI IRQs filled in on demand
+                        */
+                       irq_desc[i].chip = &no_irq_chip;
+               }
+       }
+}
+
+void init_IRQ(void) __attribute__((weak, alias("native_init_IRQ")));
+
+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]);
+       }
+
+#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);
+
+       /* Low priority IPI to cleanup after moving an irq */
+       set_intr_gate(IRQ_MOVE_CLEANUP_VECTOR, irq_move_cleanup_interrupt);
+#endif
+       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);
+
+       /* IPI vectors for APIC spurious and error interrupts */
+       alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+       alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+
+       if (!acpi_ioapic)
+               setup_irq(2, &irq2);
+}
index 0224c3637c73e68b4566124dd5d825034bc8c07a..21f2bae98c157730eff158c1f921ce3aa23882b3 100644 (file)
@@ -20,9 +20,9 @@
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_SMP
-static void flush_ldt(void *null)
+static void flush_ldt(void *current_mm)
 {
-       if (current->active_mm)
+       if (current->active_mm == current_mm)
                load_LDT(&current->active_mm->context);
 }
 #endif
@@ -68,7 +68,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
                load_LDT(pc);
                mask = cpumask_of_cpu(smp_processor_id());
                if (!cpus_equal(current->mm->cpu_vm_mask, mask))
-                       smp_call_function(flush_ldt, NULL, 1, 1);
+                       smp_call_function(flush_ldt, current->mm, 1, 1);
                preempt_enable();
 #else
                load_LDT(pc);
index d0b234c9fc318ac0f11a127f9aac87ce7de55dc6..f4960171bc66625ebac582a172990b0531031fcb 100644 (file)
@@ -39,7 +39,7 @@ static void set_idt(void *newidt, __u16 limit)
        curidt.address = (unsigned long)newidt;
 
        load_idt(&curidt);
-};
+}
 
 
 static void set_gdt(void *newgdt, __u16 limit)
@@ -51,7 +51,7 @@ static void set_gdt(void *newgdt, __u16 limit)
        curgdt.address = (unsigned long)newgdt;
 
        load_gdt(&curgdt);
-};
+}
 
 static void load_segments(void)
 {
index 576a03db45112cd710cb17e268bf226d76d36012..7830dc4a8380d4f2631beef1df15f183cd69b721 100644 (file)
@@ -110,7 +110,7 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
 {
        pgd_t *level4p;
        level4p = (pgd_t *)__va(start_pgtable);
-       return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT);
+       return init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT);
 }
 
 static void set_idt(void *newidt, u16 limit)
index 69729e38b78a2d83e7f7e799bd2ea37730305d18..9758fea87c5b4e219d8c28d7dde2260f3a5902e4 100644 (file)
@@ -5,13 +5,14 @@
  *                   2006      Shaohua Li <shaohua.li@intel.com>
  *
  *     This driver allows to upgrade microcode on Intel processors
- *     belonging to IA-32 family - PentiumPro, Pentium II, 
+ *     belonging to IA-32 family - PentiumPro, Pentium II,
  *     Pentium III, Xeon, Pentium 4, etc.
  *
- *     Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, 
- *     Order Number 245472 or free download from:
- *             
- *     http://developer.intel.com/design/pentium4/manuals/245472.htm
+ *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *     Software Developer's Manual
+ *     Order Number 253668 or free download from:
+ *
+ *     http://developer.intel.com/design/pentium4/manuals/253668.htm
  *
  *     For more information, go to http://www.urbanmyth.org/microcode
  *
  *             nature of implementation.
  *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
  *             Fix the panic when writing zero-length microcode chunk.
- *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>, 
+ *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
  *             Jun Nakajima <jun.nakajima@intel.com>
  *             Support for the microcode updates in the new format.
  *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
  *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- *             because we no longer hold a copy of applied microcode 
+ *             because we no longer hold a copy of applied microcode
  *             in kernel memory.
  *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
  *             Fix sigmatch() macro to handle old CPUs with pf == 0.
@@ -320,11 +321,11 @@ static void apply_microcode(int cpu)
                return;
 
        /* serialize access to the physical write to MSR 0x79 */
-       spin_lock_irqsave(&microcode_update_lock, flags);          
+       spin_lock_irqsave(&microcode_update_lock, flags);
 
        /* write microcode via MSR 0x79 */
        wrmsr(MSR_IA32_UCODE_WRITE,
-               (unsigned long) uci->mc->bits, 
+               (unsigned long) uci->mc->bits,
                (unsigned long) uci->mc->bits >> 16 >> 16);
        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 
@@ -341,7 +342,7 @@ static void apply_microcode(int cpu)
                return;
        }
        printk(KERN_INFO "microcode: CPU%d updated from revision "
-              "0x%x to 0x%x, date = %08x \n", 
+              "0x%x to 0x%x, date = %08x \n",
               cpu_num, uci->rev, val[1], uci->mc->hdr.date);
        uci->rev = val[1];
 }
@@ -534,7 +535,7 @@ static int cpu_request_microcode(int cpu)
                c->x86, c->x86_model, c->x86_mask);
        error = request_firmware(&firmware, name, &microcode_pdev->dev);
        if (error) {
-               pr_debug("microcode: ucode data file %s load failed\n", name);
+               pr_debug("microcode: data file %s load failed\n", name);
                return error;
        }
        buf = firmware->data;
@@ -805,6 +806,9 @@ static int __init microcode_init (void)
 {
        int error;
 
+       printk(KERN_INFO
+               "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
+
        error = microcode_dev_init();
        if (error)
                return error;
@@ -825,9 +829,6 @@ static int __init microcode_init (void)
        }
 
        register_hotcpu_notifier(&mc_cpu_notifier);
-
-       printk(KERN_INFO 
-               "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
        return 0;
 }
 
index edc5fbfe85c06eb1e2eff8aebdbcf3740b074a63..fdfdc550b366043045a34a4c476c61d6ff67b5d7 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/acpi.h>
+#include <asm/mmconfig.h>
 
 #include "../pci/pci.h"
 
index 404683b94e79592c69e04930ed385056f8f5861c..3b25e49380c6eed8ff660d409afb2deda8c428cd 100644 (file)
@@ -25,6 +25,8 @@
 #include <asm/proto.h>
 #include <asm/acpi.h>
 #include <asm/bios_ebda.h>
+#include <asm/e820.h>
+#include <asm/trampoline.h>
 
 #include <mach_apic.h>
 #ifdef CONFIG_X86_32
 #include <mach_mpparse.h>
 #endif
 
-/* Have we found an MP table */
-int smp_found_config;
-
-/*
- * Various Linux-internal data structures created from the
- * MP-table.
- */
-#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
-int mp_bus_id_to_type[MAX_MP_BUSSES];
-#endif
-
-DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
-int mp_bus_id_to_pci_bus[MAX_MP_BUSSES] = {[0 ... MAX_MP_BUSSES - 1] = -1 };
-
-static int mp_current_pci_id;
-
-int pic_mode;
-
-/*
- * Intel MP BIOS table parsing routines:
- */
-
 /*
  * Checksum an MP configuration block.
  */
@@ -69,15 +49,73 @@ static int __init mpf_checksum(unsigned char *mp, int len)
 }
 
 #ifdef CONFIG_X86_NUMAQ
+int found_numaq;
 /*
  * Have to match translation table entries to main table entries by counter
  * hence the mpc_record variable .... can't see a less disgusting way of
  * doing this ....
  */
+struct mpc_config_translation {
+       unsigned char mpc_type;
+       unsigned char trans_len;
+       unsigned char trans_type;
+       unsigned char trans_quad;
+       unsigned char trans_global;
+       unsigned char trans_local;
+       unsigned short trans_reserved;
+};
+
 
 static int mpc_record;
 static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY]
     __cpuinitdata;
+
+static inline int generate_logical_apicid(int quad, int phys_apicid)
+{
+       return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1);
+}
+
+
+static inline int mpc_apic_id(struct mpc_config_processor *m,
+                       struct mpc_config_translation *translation_record)
+{
+       int quad = translation_record->trans_quad;
+       int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid);
+
+       printk(KERN_DEBUG "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n",
+              m->mpc_apicid,
+              (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
+              (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
+              m->mpc_apicver, quad, logical_apicid);
+       return logical_apicid;
+}
+
+int mp_bus_id_to_node[MAX_MP_BUSSES];
+
+int mp_bus_id_to_local[MAX_MP_BUSSES];
+
+static void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
+       struct mpc_config_translation *translation)
+{
+       int quad = translation->trans_quad;
+       int local = translation->trans_local;
+
+       mp_bus_id_to_node[m->mpc_busid] = quad;
+       mp_bus_id_to_local[m->mpc_busid] = local;
+       printk(KERN_INFO "Bus #%d is %s (node %d)\n",
+              m->mpc_busid, name, quad);
+}
+
+int quad_local_to_mp_bus_id [NR_CPUS/4][4];
+static void mpc_oem_pci_bus(struct mpc_config_bus *m,
+       struct mpc_config_translation *translation)
+{
+       int quad = translation->trans_quad;
+       int local = translation->trans_local;
+
+       quad_local_to_mp_bus_id[quad][local] = m->mpc_busid;
+}
+
 #endif
 
 static void __cpuinit MP_processor_info(struct mpc_config_processor *m)
@@ -90,7 +128,10 @@ static void __cpuinit MP_processor_info(struct mpc_config_processor *m)
                return;
        }
 #ifdef CONFIG_X86_NUMAQ
-       apicid = mpc_apic_id(m, translation_table[mpc_record]);
+       if (found_numaq)
+               apicid = mpc_apic_id(m, translation_table[mpc_record]);
+       else
+               apicid = m->mpc_apicid;
 #else
        apicid = m->mpc_apicid;
 #endif
@@ -103,17 +144,18 @@ static void __cpuinit MP_processor_info(struct mpc_config_processor *m)
        generic_processor_info(apicid, m->mpc_apicver);
 }
 
+#ifdef CONFIG_X86_IO_APIC
 static void __init MP_bus_info(struct mpc_config_bus *m)
 {
        char str[7];
-
        memcpy(str, m->mpc_bustype, 6);
        str[6] = 0;
 
 #ifdef CONFIG_X86_NUMAQ
-       mpc_oem_bus_info(m, str, translation_table[mpc_record]);
+       if (found_numaq)
+               mpc_oem_bus_info(m, str, translation_table[mpc_record]);
 #else
-       Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
+       printk(KERN_INFO "Bus #%d is %s\n", m->mpc_busid, str);
 #endif
 
 #if MAX_MP_BUSSES < 256
@@ -132,11 +174,10 @@ static void __init MP_bus_info(struct mpc_config_bus *m)
 #endif
        } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
 #ifdef CONFIG_X86_NUMAQ
-               mpc_oem_pci_bus(m, translation_table[mpc_record]);
+               if (found_numaq)
+                       mpc_oem_pci_bus(m, translation_table[mpc_record]);
 #endif
                clear_bit(m->mpc_busid, mp_bus_not_pci);
-               mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
-               mp_current_pci_id++;
 #if defined(CONFIG_EISA) || defined (CONFIG_MCA)
                mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
        } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) {
@@ -147,6 +188,7 @@ static void __init MP_bus_info(struct mpc_config_bus *m)
        } else
                printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
 }
+#endif
 
 #ifdef CONFIG_X86_IO_APIC
 
@@ -176,18 +218,89 @@ static void __init MP_ioapic_info(struct mpc_config_ioapic *m)
        if (bad_ioapic(m->mpc_apicaddr))
                return;
 
-       mp_ioapics[nr_ioapics] = *m;
+       mp_ioapics[nr_ioapics].mp_apicaddr = m->mpc_apicaddr;
+       mp_ioapics[nr_ioapics].mp_apicid = m->mpc_apicid;
+       mp_ioapics[nr_ioapics].mp_type = m->mpc_type;
+       mp_ioapics[nr_ioapics].mp_apicver = m->mpc_apicver;
+       mp_ioapics[nr_ioapics].mp_flags = m->mpc_flags;
        nr_ioapics++;
 }
 
-static void __init MP_intsrc_info(struct mpc_config_intsrc *m)
+static void print_MP_intsrc_info(struct mpc_config_intsrc *m)
 {
-       mp_irqs[mp_irq_entries] = *m;
-       Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
+       printk(KERN_CONT "Int: type %d, pol %d, trig %d, bus %02x,"
                " IRQ %02x, APIC ID %x, APIC INT %02x\n",
                m->mpc_irqtype, m->mpc_irqflag & 3,
                (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
                m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
+}
+
+static void __init print_mp_irq_info(struct mp_config_intsrc *mp_irq)
+{
+       printk(KERN_CONT "Int: type %d, pol %d, trig %d, bus %02x,"
+               " IRQ %02x, APIC ID %x, APIC INT %02x\n",
+               mp_irq->mp_irqtype, mp_irq->mp_irqflag & 3,
+               (mp_irq->mp_irqflag >> 2) & 3, mp_irq->mp_srcbus,
+               mp_irq->mp_srcbusirq, mp_irq->mp_dstapic, mp_irq->mp_dstirq);
+}
+
+static void __init assign_to_mp_irq(struct mpc_config_intsrc *m,
+                                   struct mp_config_intsrc *mp_irq)
+{
+       mp_irq->mp_dstapic = m->mpc_dstapic;
+       mp_irq->mp_type = m->mpc_type;
+       mp_irq->mp_irqtype = m->mpc_irqtype;
+       mp_irq->mp_irqflag = m->mpc_irqflag;
+       mp_irq->mp_srcbus = m->mpc_srcbus;
+       mp_irq->mp_srcbusirq = m->mpc_srcbusirq;
+       mp_irq->mp_dstirq = m->mpc_dstirq;
+}
+
+static void __init assign_to_mpc_intsrc(struct mp_config_intsrc *mp_irq,
+                                       struct mpc_config_intsrc *m)
+{
+       m->mpc_dstapic = mp_irq->mp_dstapic;
+       m->mpc_type = mp_irq->mp_type;
+       m->mpc_irqtype = mp_irq->mp_irqtype;
+       m->mpc_irqflag = mp_irq->mp_irqflag;
+       m->mpc_srcbus = mp_irq->mp_srcbus;
+       m->mpc_srcbusirq = mp_irq->mp_srcbusirq;
+       m->mpc_dstirq = mp_irq->mp_dstirq;
+}
+
+static int __init mp_irq_mpc_intsrc_cmp(struct mp_config_intsrc *mp_irq,
+                                       struct mpc_config_intsrc *m)
+{
+       if (mp_irq->mp_dstapic != m->mpc_dstapic)
+               return 1;
+       if (mp_irq->mp_type != m->mpc_type)
+               return 2;
+       if (mp_irq->mp_irqtype != m->mpc_irqtype)
+               return 3;
+       if (mp_irq->mp_irqflag != m->mpc_irqflag)
+               return 4;
+       if (mp_irq->mp_srcbus != m->mpc_srcbus)
+               return 5;
+       if (mp_irq->mp_srcbusirq != m->mpc_srcbusirq)
+               return 6;
+       if (mp_irq->mp_dstirq != m->mpc_dstirq)
+               return 7;
+
+       return 0;
+}
+
+static void __init MP_intsrc_info(struct mpc_config_intsrc *m)
+{
+       int i;
+
+       print_MP_intsrc_info(m);
+
+       for (i = 0; i < mp_irq_entries; i++) {
+               if (!mp_irq_mpc_intsrc_cmp(&mp_irqs[i], m))
+                       return;
+       }
+
+       assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
        if (++mp_irq_entries == MAX_IRQ_SOURCES)
                panic("Max # of irq sources exceeded!!\n");
 }
@@ -196,7 +309,7 @@ static void __init MP_intsrc_info(struct mpc_config_intsrc *m)
 
 static void __init MP_lintsrc_info(struct mpc_config_lintsrc *m)
 {
-       Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
+       printk(KERN_INFO "Lint: type %d, pol %d, trig %d, bus %02x,"
                " IRQ %02x, APIC ID %x, APIC LINT %02x\n",
                m->mpc_irqtype, m->mpc_irqflag & 3,
                (m->mpc_irqflag >> 2) & 3, m->mpc_srcbusid,
@@ -266,11 +379,14 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable,
        }
 }
 
-static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,
+void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
                                 char *productid)
 {
        if (strncmp(oem, "IBM NUMA", 8))
-               printk("Warning!  May not be a NUMA-Q system!\n");
+               printk("Warning!  Not a NUMA-Q system!\n");
+       else
+               found_numaq = 1;
+
        if (mpc->mpc_oemptr)
                smp_read_mpc_oem((struct mp_config_oemtable *)mpc->mpc_oemptr,
                                 mpc->mpc_oemsize);
@@ -281,12 +397,9 @@ static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,
  * Read/parse the MPC
  */
 
-static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
+static int __init smp_check_mpc(struct mp_config_table *mpc, char *oem,
+                               char *str)
 {
-       char str[16];
-       char oem[10];
-       int count = sizeof(*mpc);
-       unsigned char *mpt = ((unsigned char *)mpc) + count;
 
        if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) {
                printk(KERN_ERR "MPTABLE: bad signature [%c%c%c%c]!\n",
@@ -309,19 +422,42 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
        }
        memcpy(oem, mpc->mpc_oem, 8);
        oem[8] = 0;
-       printk(KERN_INFO "MPTABLE: OEM ID: %s ", oem);
+       printk(KERN_INFO "MPTABLE: OEM ID: %s\n", oem);
 
        memcpy(str, mpc->mpc_productid, 12);
        str[12] = 0;
-       printk("Product ID: %s ", str);
 
-#ifdef CONFIG_X86_32
-       mps_oem_check(mpc, oem, str);
-#endif
-       printk(KERN_INFO "MPTABLE: Product ID: %s ", str);
+       printk(KERN_INFO "MPTABLE: Product ID: %s\n", str);
 
        printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic);
 
+       return 1;
+}
+
+static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
+{
+       char str[16];
+       char oem[10];
+
+       int count = sizeof(*mpc);
+       unsigned char *mpt = ((unsigned char *)mpc) + count;
+
+       if (!smp_check_mpc(mpc, oem, str))
+               return 0;
+
+#ifdef CONFIG_X86_32
+       /*
+        * need to make sure summit and es7000's mps_oem_check is safe to be
+        * called early via genericarch 's mps_oem_check
+        */
+       if (early) {
+#ifdef CONFIG_X86_NUMAQ
+               numaq_mps_oem_check(mpc, oem, str);
+#endif
+       } else
+               mps_oem_check(mpc, oem, str);
+#endif
+
        /* save the local APIC address, it might be non-default */
        if (!acpi_lapic)
                mp_lapic_addr = mpc->mpc_lapic;
@@ -352,7 +488,9 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
                        {
                                struct mpc_config_bus *m =
                                    (struct mpc_config_bus *)mpt;
+#ifdef CONFIG_X86_IO_APIC
                                MP_bus_info(m);
+#endif
                                mpt += sizeof(*m);
                                count += sizeof(*m);
                                break;
@@ -402,6 +540,11 @@ static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
                ++mpc_record;
 #endif
        }
+
+#ifdef CONFIG_X86_GENERICARCH
+       generic_bigsmp_probe();
+#endif
+
        setup_apic_routing();
        if (!num_processors)
                printk(KERN_ERR "MPTABLE: no processors registered!\n");
@@ -427,7 +570,7 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type)
        intsrc.mpc_type = MP_INTSRC;
        intsrc.mpc_irqflag = 0; /* conforming */
        intsrc.mpc_srcbus = 0;
-       intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;
+       intsrc.mpc_dstapic = mp_ioapics[0].mp_apicid;
 
        intsrc.mpc_irqtype = mp_INT;
 
@@ -488,40 +631,11 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type)
        MP_intsrc_info(&intsrc);
 }
 
-#endif
 
-static inline void __init construct_default_ISA_mptable(int mpc_default_type)
+static void construct_ioapic_table(int mpc_default_type)
 {
-       struct mpc_config_processor processor;
-       struct mpc_config_bus bus;
-#ifdef CONFIG_X86_IO_APIC
        struct mpc_config_ioapic ioapic;
-#endif
-       struct mpc_config_lintsrc lintsrc;
-       int linttypes[2] = { mp_ExtINT, mp_NMI };
-       int i;
-
-       /*
-        * local APIC has default address
-        */
-       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-
-       /*
-        * 2 CPUs, numbered 0 & 1.
-        */
-       processor.mpc_type = MP_PROCESSOR;
-       /* Either an integrated APIC or a discrete 82489DX. */
-       processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
-       processor.mpc_cpuflag = CPU_ENABLED;
-       processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
-           (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
-       processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
-       processor.mpc_reserved[0] = 0;
-       processor.mpc_reserved[1] = 0;
-       for (i = 0; i < 2; i++) {
-               processor.mpc_apicid = i;
-               MP_processor_info(&processor);
-       }
+       struct mpc_config_bus bus;
 
        bus.mpc_type = MP_BUS;
        bus.mpc_busid = 0;
@@ -550,7 +664,6 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
                MP_bus_info(&bus);
        }
 
-#ifdef CONFIG_X86_IO_APIC
        ioapic.mpc_type = MP_IOAPIC;
        ioapic.mpc_apicid = 2;
        ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
@@ -562,7 +675,42 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
         * We set up most of the low 16 IO-APIC pins according to MPS rules.
         */
        construct_default_ioirq_mptable(mpc_default_type);
+}
+#else
+static inline void construct_ioapic_table(int mpc_default_type) { }
 #endif
+
+static inline void __init construct_default_ISA_mptable(int mpc_default_type)
+{
+       struct mpc_config_processor processor;
+       struct mpc_config_lintsrc lintsrc;
+       int linttypes[2] = { mp_ExtINT, mp_NMI };
+       int i;
+
+       /*
+        * local APIC has default address
+        */
+       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+       /*
+        * 2 CPUs, numbered 0 & 1.
+        */
+       processor.mpc_type = MP_PROCESSOR;
+       /* Either an integrated APIC or a discrete 82489DX. */
+       processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
+       processor.mpc_cpuflag = CPU_ENABLED;
+       processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
+           (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
+       processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
+       processor.mpc_reserved[0] = 0;
+       processor.mpc_reserved[1] = 0;
+       for (i = 0; i < 2; i++) {
+               processor.mpc_apicid = i;
+               MP_processor_info(&processor);
+       }
+
+       construct_ioapic_table(mpc_default_type);
+
        lintsrc.mpc_type = MP_LINTSRC;
        lintsrc.mpc_irqflag = 0;        /* conforming */
        lintsrc.mpc_srcbusid = 0;
@@ -577,13 +725,23 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
 
 static struct intel_mp_floating *mpf_found;
 
+/*
+ * Machine specific quirk for finding the SMP config before other setup
+ * activities destroy the table:
+ */
+int (*mach_get_smp_config_quirk)(unsigned int early);
+
 /*
  * Scan the memory blocks for an SMP configuration block.
  */
-static void __init __get_smp_config(unsigned early)
+static void __init __get_smp_config(unsigned int early)
 {
        struct intel_mp_floating *mpf = mpf_found;
 
+       if (mach_get_smp_config_quirk) {
+               if (mach_get_smp_config_quirk(early))
+                       return;
+       }
        if (acpi_lapic && early)
                return;
        /*
@@ -600,7 +758,7 @@ static void __init __get_smp_config(unsigned early)
 
        printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
               mpf->mpf_specification);
-#ifdef CONFIG_X86_32
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
        if (mpf->mpf_feature2 & (1 << 7)) {
                printk(KERN_INFO "    IMCR and PIC compatibility mode.\n");
                pic_mode = 1;
@@ -632,7 +790,9 @@ static void __init __get_smp_config(unsigned early)
                 * override the defaults.
                 */
                if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr), early)) {
+#ifdef CONFIG_X86_LOCAL_APIC
                        smp_found_config = 0;
+#endif
                        printk(KERN_ERR
                               "BIOS bug, MP table errors detected!...\n");
                        printk(KERN_ERR "... disabling SMP support. "
@@ -689,7 +849,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
        unsigned int *bp = phys_to_virt(base);
        struct intel_mp_floating *mpf;
 
-       Dprintk("Scan SMP from %p for %ld bytes.\n", bp, length);
+       printk(KERN_DEBUG "Scan SMP from %p for %ld bytes.\n", bp, length);
        BUILD_BUG_ON(sizeof(*mpf) != 16);
 
        while (length > 0) {
@@ -699,15 +859,21 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
                    !mpf_checksum((unsigned char *)bp, 16) &&
                    ((mpf->mpf_specification == 1)
                     || (mpf->mpf_specification == 4))) {
-
+#ifdef CONFIG_X86_LOCAL_APIC
                        smp_found_config = 1;
+#endif
                        mpf_found = mpf;
-#ifdef CONFIG_X86_32
+
                        printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n",
                               mpf, virt_to_phys(mpf));
-                       reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE,
+
+                       if (!reserve)
+                               return 1;
+                       reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE,
                                        BOOTMEM_DEFAULT);
                        if (mpf->mpf_physptr) {
+                               unsigned long size = PAGE_SIZE;
+#ifdef CONFIG_X86_32
                                /*
                                 * We cannot access to MPC table to compute
                                 * table size yet, as only few megabytes from
@@ -717,24 +883,15 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
                                 * PAGE_SIZE from mpg->mpf_physptr yields BUG()
                                 * in reserve_bootmem.
                                 */
-                               unsigned long size = PAGE_SIZE;
                                unsigned long end = max_low_pfn * PAGE_SIZE;
                                if (mpf->mpf_physptr + size > end)
                                        size = end - mpf->mpf_physptr;
-                               reserve_bootmem(mpf->mpf_physptr, size,
+#endif
+                               reserve_bootmem_generic(mpf->mpf_physptr, size,
                                                BOOTMEM_DEFAULT);
                        }
 
-#else
-                       if (!reserve)
-                               return 1;
-
-                       reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE);
-                       if (mpf->mpf_physptr)
-                               reserve_bootmem_generic(mpf->mpf_physptr,
-                                                       PAGE_SIZE);
-#endif
-               return 1;
+                       return 1;
                }
                bp += 4;
                length -= 16;
@@ -742,10 +899,16 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
        return 0;
 }
 
-static void __init __find_smp_config(unsigned reserve)
+int (*mach_find_smp_config_quirk)(unsigned int reserve);
+
+static void __init __find_smp_config(unsigned int reserve)
 {
        unsigned int address;
 
+       if (mach_find_smp_config_quirk) {
+               if (mach_find_smp_config_quirk(reserve))
+                       return;
+       }
        /*
         * FIXME: Linux assumes you have 640K of base ram..
         * this continues the error...
@@ -790,298 +953,294 @@ void __init find_smp_config(void)
        __find_smp_config(1);
 }
 
-/* --------------------------------------------------------------------------
-                            ACPI-based MP Configuration
-   -------------------------------------------------------------------------- */
+#ifdef CONFIG_X86_IO_APIC
+static u8 __initdata irq_used[MAX_IRQ_SOURCES];
 
-/*
- * Keep this outside and initialized to 0, for !CONFIG_ACPI builds:
- */
-int es7000_plat;
+static int  __init get_MP_intsrc_index(struct mpc_config_intsrc *m)
+{
+       int i;
 
-#ifdef CONFIG_ACPI
+       if (m->mpc_irqtype != mp_INT)
+               return 0;
 
-#ifdef CONFIG_X86_IO_APIC
+       if (m->mpc_irqflag != 0x0f)
+               return 0;
 
-#define MP_ISA_BUS             0
+       /* not legacy */
 
-extern struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];
+       for (i = 0; i < mp_irq_entries; i++) {
+               if (mp_irqs[i].mp_irqtype != mp_INT)
+                       continue;
 
-static int mp_find_ioapic(int gsi)
-{
-       int i = 0;
+               if (mp_irqs[i].mp_irqflag != 0x0f)
+                       continue;
 
-       /* Find the IOAPIC that manages this GSI. */
-       for (i = 0; i < nr_ioapics; i++) {
-               if ((gsi >= mp_ioapic_routing[i].gsi_base)
-                   && (gsi <= mp_ioapic_routing[i].gsi_end))
-                       return i;
+               if (mp_irqs[i].mp_srcbus != m->mpc_srcbus)
+                       continue;
+               if (mp_irqs[i].mp_srcbusirq != m->mpc_srcbusirq)
+                       continue;
+               if (irq_used[i]) {
+                       /* already claimed */
+                       return -2;
+               }
+               irq_used[i] = 1;
+               return i;
        }
 
-       printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
+       /* not found */
        return -1;
 }
 
-static u8 __init uniq_ioapic_id(u8 id)
-{
-#ifdef CONFIG_X86_32
-       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-           !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
-               return io_apic_get_unique_id(nr_ioapics, id);
-       else
-               return id;
-#else
-       int i;
-       DECLARE_BITMAP(used, 256);
-       bitmap_zero(used, 256);
-       for (i = 0; i < nr_ioapics; i++) {
-               struct mpc_config_ioapic *ia = &mp_ioapics[i];
-               __set_bit(ia->mpc_apicid, used);
-       }
-       if (!test_bit(id, used))
-               return id;
-       return find_first_zero_bit(used, 256);
+#define SPARE_SLOT_NUM 20
+
+static struct mpc_config_intsrc __initdata *m_spare[SPARE_SLOT_NUM];
 #endif
-}
 
-void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
+static int  __init replace_intsrc_all(struct mp_config_table *mpc,
+                                       unsigned long mpc_new_phys,
+                                       unsigned long mpc_new_length)
 {
-       int idx = 0;
-
-       if (bad_ioapic(address))
-               return;
+#ifdef CONFIG_X86_IO_APIC
+       int i;
+       int nr_m_spare = 0;
+#endif
 
-       idx = nr_ioapics;
+       int count = sizeof(*mpc);
+       unsigned char *mpt = ((unsigned char *)mpc) + count;
 
-       mp_ioapics[idx].mpc_type = MP_IOAPIC;
-       mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
-       mp_ioapics[idx].mpc_apicaddr = address;
+       printk(KERN_INFO "mpc_length %x\n", mpc->mpc_length);
+       while (count < mpc->mpc_length) {
+               switch (*mpt) {
+               case MP_PROCESSOR:
+                       {
+                               struct mpc_config_processor *m =
+                                   (struct mpc_config_processor *)mpt;
+                               mpt += sizeof(*m);
+                               count += sizeof(*m);
+                               break;
+                       }
+               case MP_BUS:
+                       {
+                               struct mpc_config_bus *m =
+                                   (struct mpc_config_bus *)mpt;
+                               mpt += sizeof(*m);
+                               count += sizeof(*m);
+                               break;
+                       }
+               case MP_IOAPIC:
+                       {
+                               mpt += sizeof(struct mpc_config_ioapic);
+                               count += sizeof(struct mpc_config_ioapic);
+                               break;
+                       }
+               case MP_INTSRC:
+                       {
+#ifdef CONFIG_X86_IO_APIC
+                               struct mpc_config_intsrc *m =
+                                   (struct mpc_config_intsrc *)mpt;
 
-       set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-       mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
-#ifdef CONFIG_X86_32
-       mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
-#else
-       mp_ioapics[idx].mpc_apicver = 0;
+                               printk(KERN_INFO "OLD ");
+                               print_MP_intsrc_info(m);
+                               i = get_MP_intsrc_index(m);
+                               if (i > 0) {
+                                       assign_to_mpc_intsrc(&mp_irqs[i], m);
+                                       printk(KERN_INFO "NEW ");
+                                       print_mp_irq_info(&mp_irqs[i]);
+                               } else if (!i) {
+                                       /* legacy, do nothing */
+                               } else if (nr_m_spare < SPARE_SLOT_NUM) {
+                                       /*
+                                        * not found (-1), or duplicated (-2)
+                                        * are invalid entries,
+                                        * we need to use the slot  later
+                                        */
+                                       m_spare[nr_m_spare] = m;
+                                       nr_m_spare++;
+                               }
 #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].mpc_apicid;
-       mp_ioapic_routing[idx].gsi_base = gsi_base;
-       mp_ioapic_routing[idx].gsi_end = gsi_base +
-           io_apic_get_redir_entries(idx);
-
-       printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
-              "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
-              mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
-              mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end);
-
-       nr_ioapics++;
-}
+                               mpt += sizeof(struct mpc_config_intsrc);
+                               count += sizeof(struct mpc_config_intsrc);
+                               break;
+                       }
+               case MP_LINTSRC:
+                       {
+                               struct mpc_config_lintsrc *m =
+                                   (struct mpc_config_lintsrc *)mpt;
+                               mpt += sizeof(*m);
+                               count += sizeof(*m);
+                               break;
+                       }
+               default:
+                       /* wrong mptable */
+                       printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n");
+                       printk(KERN_ERR "type %x\n", *mpt);
+                       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
+                                       1, mpc, mpc->mpc_length, 1);
+                       goto out;
+               }
+       }
 
-void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
-{
-       struct mpc_config_intsrc intsrc;
-       int ioapic = -1;
-       int pin = -1;
+#ifdef CONFIG_X86_IO_APIC
+       for (i = 0; i < mp_irq_entries; i++) {
+               if (irq_used[i])
+                       continue;
 
-       /*
-        * Convert 'gsi' to 'ioapic.pin'.
-        */
-       ioapic = mp_find_ioapic(gsi);
-       if (ioapic < 0)
-               return;
-       pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
+               if (mp_irqs[i].mp_irqtype != mp_INT)
+                       continue;
 
-       /*
-        * TBD: This check is for faulty timer entries, where the override
-        *      erroneously sets the trigger to level, resulting in a HUGE
-        *      increase of timer interrupts!
-        */
-       if ((bus_irq == 0) && (trigger == 3))
-               trigger = 1;
+               if (mp_irqs[i].mp_irqflag != 0x0f)
+                       continue;
 
-       intsrc.mpc_type = MP_INTSRC;
-       intsrc.mpc_irqtype = mp_INT;
-       intsrc.mpc_irqflag = (trigger << 2) | polarity;
-       intsrc.mpc_srcbus = MP_ISA_BUS;
-       intsrc.mpc_srcbusirq = bus_irq; /* IRQ */
-       intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;     /* APIC ID */
-       intsrc.mpc_dstirq = pin;        /* INTIN# */
+               if (nr_m_spare > 0) {
+                       printk(KERN_INFO "*NEW* found ");
+                       nr_m_spare--;
+                       assign_to_mpc_intsrc(&mp_irqs[i], m_spare[nr_m_spare]);
+                       m_spare[nr_m_spare] = NULL;
+               } else {
+                       struct mpc_config_intsrc *m =
+                           (struct mpc_config_intsrc *)mpt;
+                       count += sizeof(struct mpc_config_intsrc);
+                       if (!mpc_new_phys) {
+                               printk(KERN_INFO "No spare slots, try to append...take your risk, new mpc_length %x\n", count);
+                       } else {
+                               if (count <= mpc_new_length)
+                                       printk(KERN_INFO "No spare slots, try to append..., new mpc_length %x\n", count);
+                               else {
+                                       printk(KERN_ERR "mpc_new_length %lx is too small\n", mpc_new_length);
+                                       goto out;
+                               }
+                       }
+                       assign_to_mpc_intsrc(&mp_irqs[i], m);
+                       mpc->mpc_length = count;
+                       mpt += sizeof(struct mpc_config_intsrc);
+               }
+               print_mp_irq_info(&mp_irqs[i]);
+       }
+#endif
+out:
+       /* update checksum */
+       mpc->mpc_checksum = 0;
+       mpc->mpc_checksum -= mpf_checksum((unsigned char *)mpc,
+                                          mpc->mpc_length);
 
-       MP_intsrc_info(&intsrc);
+       return 0;
 }
 
-void __init mp_config_acpi_legacy_irqs(void)
-{
-       struct mpc_config_intsrc intsrc;
-       int i = 0;
-       int ioapic = -1;
+static int __initdata enable_update_mptable;
 
-#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
-       /*
-        * Fabricate the legacy ISA bus (bus #31).
-        */
-       mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
-#endif
-       set_bit(MP_ISA_BUS, mp_bus_not_pci);
-       Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
+static int __init update_mptable_setup(char *str)
+{
+       enable_update_mptable = 1;
+       return 0;
+}
+early_param("update_mptable", update_mptable_setup);
 
-       /*
-        * Older generations of ES7000 have no legacy identity mappings
-        */
-       if (es7000_plat == 1)
-               return;
+static unsigned long __initdata mpc_new_phys;
+static unsigned long mpc_new_length __initdata = 4096;
 
-       /*
-        * Locate the IOAPIC that manages the ISA IRQs (0-15).
-        */
-       ioapic = mp_find_ioapic(0);
-       if (ioapic < 0)
-               return;
+/* alloc_mptable or alloc_mptable=4k */
+static int __initdata alloc_mptable;
+static int __init parse_alloc_mptable_opt(char *p)
+{
+       enable_update_mptable = 1;
+       alloc_mptable = 1;
+       if (!p)
+               return 0;
+       mpc_new_length = memparse(p, &p);
+       return 0;
+}
+early_param("alloc_mptable", parse_alloc_mptable_opt);
 
-       intsrc.mpc_type = MP_INTSRC;
-       intsrc.mpc_irqflag = 0; /* Conforming */
-       intsrc.mpc_srcbus = MP_ISA_BUS;
-#ifdef CONFIG_X86_IO_APIC
-       intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
+void __init early_reserve_e820_mpc_new(void)
+{
+       if (enable_update_mptable && alloc_mptable) {
+               u64 startt = 0;
+#ifdef CONFIG_X86_TRAMPOLINE
+               startt = TRAMPOLINE_BASE;
 #endif
-       /*
-        * Use the default configuration for the IRQs 0-15.  Unless
-        * overridden by (MADT) interrupt source override entries.
-        */
-       for (i = 0; i < 16; i++) {
-               int idx;
-
-               for (idx = 0; idx < mp_irq_entries; idx++) {
-                       struct mpc_config_intsrc *irq = mp_irqs + idx;
-
-                       /* Do we already have a mapping for this ISA IRQ? */
-                       if (irq->mpc_srcbus == MP_ISA_BUS
-                           && irq->mpc_srcbusirq == i)
-                               break;
-
-                       /* Do we already have a mapping for this IOAPIC pin */
-                       if ((irq->mpc_dstapic == intsrc.mpc_dstapic) &&
-                           (irq->mpc_dstirq == i))
-                               break;
-               }
-
-               if (idx != mp_irq_entries) {
-                       printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
-                       continue;       /* IRQ already used */
-               }
-
-               intsrc.mpc_irqtype = mp_INT;
-               intsrc.mpc_srcbusirq = i;       /* Identity mapped */
-               intsrc.mpc_dstirq = i;
-
-               MP_intsrc_info(&intsrc);
+               mpc_new_phys = early_reserve_e820(startt, mpc_new_length, 4);
        }
 }
 
-int mp_register_gsi(u32 gsi, int triggering, int polarity)
+static int __init update_mp_table(void)
 {
-       int ioapic;
-       int ioapic_pin;
-#ifdef CONFIG_X86_32
-#define MAX_GSI_NUM    4096
-#define IRQ_COMPRESSION_START  64
+       char str[16];
+       char oem[10];
+       struct intel_mp_floating *mpf;
+       struct mp_config_table *mpc;
+       struct mp_config_table *mpc_new;
+
+       if (!enable_update_mptable)
+               return 0;
+
+       mpf = mpf_found;
+       if (!mpf)
+               return 0;
 
-       static int pci_irq = IRQ_COMPRESSION_START;
        /*
-        * Mapping between Global System Interrupts, which
-        * represent all possible interrupts, and IRQs
-        * assigned to actual devices.
+        * Now see if we need to go further.
         */
-       static int gsi_to_irq[MAX_GSI_NUM];
-#else
-
-       if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
-               return gsi;
-#endif
+       if (mpf->mpf_feature1 != 0)
+               return 0;
 
-       /* Don't set up the ACPI SCI because it's already set up */
-       if (acpi_gbl_FADT.sci_interrupt == gsi)
-               return gsi;
+       if (!mpf->mpf_physptr)
+               return 0;
 
-       ioapic = mp_find_ioapic(gsi);
-       if (ioapic < 0) {
-               printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
-               return gsi;
-       }
+       mpc = phys_to_virt(mpf->mpf_physptr);
 
-       ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
+       if (!smp_check_mpc(mpc, oem, str))
+               return 0;
 
-#ifdef CONFIG_X86_32
-       if (ioapic_renumber_irq)
-               gsi = ioapic_renumber_irq(ioapic, gsi);
-#endif
+       printk(KERN_INFO "mpf: %lx\n", virt_to_phys(mpf));
+       printk(KERN_INFO "mpf_physptr: %x\n", mpf->mpf_physptr);
 
-       /*
-        * 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,
-                      ioapic_pin);
-               return gsi;
+       if (mpc_new_phys && mpc->mpc_length > mpc_new_length) {
+               mpc_new_phys = 0;
+               printk(KERN_INFO "mpc_new_length is %ld, please use alloc_mptable=8k\n",
+                        mpc_new_length);
        }
-       if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) {
-               Dprintk(KERN_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
+
+       if (!mpc_new_phys) {
+               unsigned char old, new;
+               /* check if we can change the postion */
+               mpc->mpc_checksum = 0;
+               old = mpf_checksum((unsigned char *)mpc, mpc->mpc_length);
+               mpc->mpc_checksum = 0xff;
+               new = mpf_checksum((unsigned char *)mpc, mpc->mpc_length);
+               if (old == new) {
+                       printk(KERN_INFO "mpc is readonly, please try alloc_mptable instead\n");
+                       return 0;
+               }
+               printk(KERN_INFO "use in-positon replacing\n");
+       } else {
+               mpf->mpf_physptr = mpc_new_phys;
+               mpc_new = phys_to_virt(mpc_new_phys);
+               memcpy(mpc_new, mpc, mpc->mpc_length);
+               mpc = mpc_new;
+               /* check if we can modify that */
+               if (mpc_new_phys - mpf->mpf_physptr) {
+                       struct intel_mp_floating *mpf_new;
+                       /* steal 16 bytes from [0, 1k) */
+                       printk(KERN_INFO "mpf new: %x\n", 0x400 - 16);
+                       mpf_new = phys_to_virt(0x400 - 16);
+                       memcpy(mpf_new, mpf, 16);
+                       mpf = mpf_new;
+                       mpf->mpf_physptr = mpc_new_phys;
+               }
+               mpf->mpf_checksum = 0;
+               mpf->mpf_checksum -= mpf_checksum((unsigned char *)mpf, 16);
+               printk(KERN_INFO "mpf_physptr new: %x\n", mpf->mpf_physptr);
        }
 
-       set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed);
-#ifdef CONFIG_X86_32
        /*
-        * For GSI >= 64, use IRQ compression
+        * only replace the one with mp_INT and
+        *       MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
+        * already in mp_irqs , stored by ... and mp_config_acpi_gsi,
+        * may need pci=routeirq for all coverage
         */
-       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;
+       replace_intsrc_all(mpc, mpc_new_phys, mpc_new_length);
+
+       return 0;
 }
 
-#endif /* CONFIG_X86_IO_APIC */
-#endif /* CONFIG_ACPI */
+late_initcall(update_mp_table);
similarity index 68%
rename from arch/x86/kernel/nmi_32.c
rename to arch/x86/kernel/nmi.c
index 84160f74eeb0abadbb9bcbffaef9e19ba58164a6..716b89284be02841cf74e81a73ad0d0a203cbfca 100644 (file)
  *  Mikael Pettersson  : PM converted to driver model. Disable/enable API.
  */
 
+#include <asm/apic.h>
+
+#include <linux/nmi.h>
+#include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/nmi.h>
 #include <linux/sysdev.h>
 #include <linux/sysctl.h>
 #include <linux/percpu.h>
 #include <linux/cpumask.h>
 #include <linux/kernel_stat.h>
 #include <linux/kdebug.h>
-#include <linux/slab.h>
+#include <linux/smp.h>
 
+#include <asm/i8259.h>
+#include <asm/io_apic.h>
 #include <asm/smp.h>
 #include <asm/nmi.h>
+#include <asm/proto.h>
+#include <asm/timer.h>
 
-#include "mach_traps.h"
+#include <asm/mce.h>
+
+#include <mach_traps.h>
 
 int unknown_nmi_panic;
 int nmi_watchdog_enabled;
@@ -41,28 +50,65 @@ static cpumask_t backtrace_mask = CPU_MASK_NONE;
  *  0: the lapic NMI watchdog is disabled, but can be enabled
  */
 atomic_t nmi_active = ATOMIC_INIT(0);          /* oprofile uses this */
+EXPORT_SYMBOL(nmi_active);
 
-unsigned int nmi_watchdog = NMI_DEFAULT;
-static unsigned int nmi_hz = HZ;
+unsigned int nmi_watchdog = NMI_NONE;
+EXPORT_SYMBOL(nmi_watchdog);
 
+static int panic_on_timeout;
+
+static unsigned int nmi_hz = HZ;
 static DEFINE_PER_CPU(short, wd_enabled);
+static int endflag __initdata;
 
-static int endflag __initdata = 0;
+static inline unsigned int get_nmi_count(int cpu)
+{
+#ifdef CONFIG_X86_64
+       return cpu_pda(cpu)->__nmi_count;
+#else
+       return nmi_count(cpu);
+#endif
+}
+
+static inline int mce_in_progress(void)
+{
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+       return atomic_read(&mce_entry) > 0;
+#endif
+       return 0;
+}
+
+/*
+ * Take the local apic timer and PIT/HPET into account. We don't
+ * know which one is active, when we have highres/dyntick on
+ */
+static inline unsigned int get_timer_irqs(int cpu)
+{
+#ifdef CONFIG_X86_64
+       return read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
+#else
+       return per_cpu(irq_stat, cpu).apic_timer_irqs +
+               per_cpu(irq_stat, cpu).irq0_irqs;
+#endif
+}
 
 #ifdef CONFIG_SMP
-/* The performance counters used by NMI_LOCAL_APIC don't trigger when
+/*
+ * The performance counters used by NMI_LOCAL_APIC don't trigger when
  * the CPU is idle. To make sure the NMI watchdog really ticks on all
  * CPUs during the test make them busy.
  */
 static __init void nmi_cpu_busy(void *data)
 {
        local_irq_enable_in_hardirq();
-       /* Intentionally don't use cpu_relax here. This is
-          to make sure that the performance counter really ticks,
-          even if there is a simulator or similar that catches the
-          pause instruction. On a real HT machine this is fine because
-          all other CPUs are busy with "useless" delay loops and don't
-          care if they get somewhat less cycles. */
+       /*
+        * Intentionally don't use cpu_relax here. This is
+        * to make sure that the performance counter really ticks,
+        * even if there is a simulator or similar that catches the
+        * pause instruction. On a real HT machine this is fine because
+        * all other CPUs are busy with "useless" delay loops and don't
+        * care if they get somewhat less cycles.
+        */
        while (endflag == 0)
                mb();
 }
@@ -73,15 +119,12 @@ int __init check_nmi_watchdog(void)
        unsigned int *prev_nmi_count;
        int cpu;
 
-       if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DISABLED))
-               return 0;
-
-       if (!atomic_read(&nmi_active))
+       if (!nmi_watchdog_active() || !atomic_read(&nmi_active))
                return 0;
 
-       prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
+       prev_nmi_count = kmalloc(nr_cpu_ids * sizeof(int), GFP_KERNEL);
        if (!prev_nmi_count)
-               return -1;
+               goto error;
 
        printk(KERN_INFO "Testing NMI watchdog ... ");
 
@@ -91,25 +134,19 @@ int __init check_nmi_watchdog(void)
 #endif
 
        for_each_possible_cpu(cpu)
-               prev_nmi_count[cpu] = nmi_count(cpu);
+               prev_nmi_count[cpu] = get_nmi_count(cpu);
        local_irq_enable();
-       mdelay((20*1000)/nmi_hz); // wait 20 ticks
+       mdelay((20 * 1000) / nmi_hz); /* wait 20 ticks */
 
-       for_each_possible_cpu(cpu) {
-#ifdef CONFIG_SMP
-               /* Check cpu_callin_map here because that is set
-                  after the timer is started. */
-               if (!cpu_isset(cpu, cpu_callin_map))
-                       continue;
-#endif
+       for_each_online_cpu(cpu) {
                if (!per_cpu(wd_enabled, cpu))
                        continue;
-               if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
+               if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
                        printk(KERN_WARNING "WARNING: CPU#%d: NMI "
                                "appears to be stuck (%d->%d)!\n",
                                cpu,
                                prev_nmi_count[cpu],
-                               nmi_count(cpu));
+                               get_nmi_count(cpu));
                        per_cpu(wd_enabled, cpu) = 0;
                        atomic_dec(&nmi_active);
                }
@@ -118,37 +155,53 @@ int __init check_nmi_watchdog(void)
        if (!atomic_read(&nmi_active)) {
                kfree(prev_nmi_count);
                atomic_set(&nmi_active, -1);
-               return -1;
+               goto error;
        }
        printk("OK.\n");
 
-       /* now that we know it works we can reduce NMI frequency to
-          something more reasonable; makes a difference in some configs */
+       /*
+        * now that we know it works we can reduce NMI frequency to
+        * something more reasonable; makes a difference in some configs
+        */
        if (nmi_watchdog == NMI_LOCAL_APIC)
                nmi_hz = lapic_adjust_nmi_hz(1);
 
        kfree(prev_nmi_count);
        return 0;
+error:
+       if (nmi_watchdog == NMI_IO_APIC && !timer_through_8259)
+               disable_8259A_irq(0);
+#ifdef CONFIG_X86_32
+       timer_ack = 0;
+#endif
+       return -1;
 }
 
 static int __init setup_nmi_watchdog(char *str)
 {
-       int nmi;
+       unsigned int nmi;
+
+       if (!strncmp(str, "panic", 5)) {
+               panic_on_timeout = 1;
+               str = strchr(str, ',');
+               if (!str)
+                       return 1;
+               ++str;
+       }
 
        get_option(&str, &nmi);
 
-       if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
+       if (nmi >= NMI_INVALID)
                return 0;
 
        nmi_watchdog = nmi;
        return 1;
 }
-
 __setup("nmi_watchdog=", setup_nmi_watchdog);
 
-
-/* Suspend/resume support */
-
+/*
+ * Suspend/resume support
+ */
 #ifdef CONFIG_PM
 
 static int nmi_pm_active; /* nmi_active before suspend */
@@ -172,7 +225,6 @@ static int lapic_nmi_resume(struct sys_device *dev)
        return 0;
 }
 
-
 static struct sysdev_class nmi_sysclass = {
        .name           = "lapic_nmi",
        .resume         = lapic_nmi_resume,
@@ -188,7 +240,8 @@ static int __init init_lapic_nmi_sysfs(void)
 {
        int error;
 
-       /* should really be a BUG_ON but b/c this is an
+       /*
+        * should really be a BUG_ON but b/c this is an
         * init call, it just doesn't work.  -dcz
         */
        if (nmi_watchdog != NMI_LOCAL_APIC)
@@ -202,6 +255,7 @@ static int __init init_lapic_nmi_sysfs(void)
                error = sysdev_register(&device_lapic_nmi);
        return error;
 }
+
 /* must come after the local APIC's device_initcall() */
 late_initcall(init_lapic_nmi_sysfs);
 
@@ -223,7 +277,7 @@ void acpi_nmi_enable(void)
 
 static void __acpi_nmi_disable(void *__unused)
 {
-       apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
+       apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
 }
 
 /*
@@ -242,12 +296,13 @@ void setup_apic_nmi_watchdog(void *unused)
 
        /* cheap hack to support suspend/resume */
        /* if cpu0 is not active neither should the other cpus */
-       if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
+       if (smp_processor_id() != 0 && atomic_read(&nmi_active) <= 0)
                return;
 
        switch (nmi_watchdog) {
        case NMI_LOCAL_APIC:
-               __get_cpu_var(wd_enabled) = 1; /* enable it before to avoid race with handler */
+                /* enable it before to avoid race with handler */
+               __get_cpu_var(wd_enabled) = 1;
                if (lapic_watchdog_init(nmi_hz) < 0) {
                        __get_cpu_var(wd_enabled) = 0;
                        return;
@@ -262,9 +317,8 @@ void setup_apic_nmi_watchdog(void *unused)
 void stop_apic_nmi_watchdog(void *unused)
 {
        /* only support LOCAL and IO APICs for now */
-       if ((nmi_watchdog != NMI_LOCAL_APIC) &&
-           (nmi_watchdog != NMI_IO_APIC))
-               return;
+       if (!nmi_watchdog_active())
+               return;
        if (__get_cpu_var(wd_enabled) == 0)
                return;
        if (nmi_watchdog == NMI_LOCAL_APIC)
@@ -284,26 +338,26 @@ void stop_apic_nmi_watchdog(void *unused)
  * since NMIs don't listen to _any_ locks, we have to be extremely
  * careful not to rely on unsafe variables. The printk might lock
  * up though, so we have to break up any console locks first ...
- * [when there will be more tty-related locks, break them up
- *  here too!]
+ * [when there will be more tty-related locks, break them up here too!]
  */
 
-static unsigned int
-       last_irq_sums [NR_CPUS],
-       alert_counter [NR_CPUS];
+static DEFINE_PER_CPU(unsigned, last_irq_sum);
+static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(int, nmi_touch);
 
 void touch_nmi_watchdog(void)
 {
-       if (nmi_watchdog > 0) {
+       if (nmi_watchdog_active()) {
                unsigned cpu;
 
                /*
-                * Just reset the alert counters, (other CPUs might be
-                * spinning on locks we hold):
+                * Tell other CPUs to reset their alert counters. We cannot
+                * do it ourselves because the alert count increase is not
+                * atomic.
                 */
                for_each_present_cpu(cpu) {
-                       if (alert_counter[cpu])
-                               alert_counter[cpu] = 0;
+                       if (per_cpu(nmi_touch, cpu) != 1)
+                               per_cpu(nmi_touch, cpu) = 1;
                }
        }
 
@@ -314,12 +368,9 @@ void touch_nmi_watchdog(void)
 }
 EXPORT_SYMBOL(touch_nmi_watchdog);
 
-extern void die_nmi(struct pt_regs *, const char *msg);
-
 notrace __kprobes int
 nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
 {
-
        /*
         * Since current_thread_info()-> is always on the stack, and we
         * always switch the stack NMI-atomically, it's safe to use
@@ -337,39 +388,45 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
                touched = 1;
        }
 
+       sum = get_timer_irqs(cpu);
+
+       if (__get_cpu_var(nmi_touch)) {
+               __get_cpu_var(nmi_touch) = 0;
+               touched = 1;
+       }
+
        if (cpu_isset(cpu, backtrace_mask)) {
                static DEFINE_SPINLOCK(lock);   /* Serialise the printks */
 
                spin_lock(&lock);
-               printk("NMI backtrace for cpu %d\n", cpu);
+               printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
                dump_stack();
                spin_unlock(&lock);
                cpu_clear(cpu, backtrace_mask);
        }
 
-       /*
-        * Take the local apic timer and PIT/HPET into account. We don't
-        * know which one is active, when we have highres/dyntick on
-        */
-       sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
-               per_cpu(irq_stat, cpu).irq0_irqs;
+       /* Could check oops_in_progress here too, but it's safer not to */
+       if (mce_in_progress())
+               touched = 1;
 
        /* if the none of the timers isn't firing, this cpu isn't doing much */
-       if (!touched && last_irq_sums[cpu] == sum) {
+       if (!touched && __get_cpu_var(last_irq_sum) == sum) {
                /*
                 * Ayiee, looks like this CPU is stuck ...
                 * wait a few IRQs (5 seconds) before doing the oops ...
                 */
-               alert_counter[cpu]++;
-               if (alert_counter[cpu] == 5*nmi_hz)
+               local_inc(&__get_cpu_var(alert_counter));
+               if (local_read(&__get_cpu_var(alert_counter)) == 5 * nmi_hz)
                        /*
                         * die_nmi will return ONLY if NOTIFY_STOP happens..
                         */
-                       die_nmi(regs, "BUG: NMI Watchdog detected LOCKUP");
+                       die_nmi("BUG: NMI Watchdog detected LOCKUP",
+                               regs, panic_on_timeout);
        } else {
-               last_irq_sums[cpu] = sum;
-               alert_counter[cpu] = 0;
+               __get_cpu_var(last_irq_sum) = sum;
+               local_set(&__get_cpu_var(alert_counter), 0);
        }
+
        /* see if the nmi watchdog went off */
        if (!__get_cpu_var(wd_enabled))
                return rc;
@@ -378,7 +435,8 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
                rc |= lapic_wd_event(nmi_hz);
                break;
        case NMI_IO_APIC:
-               /* don't know how to accurately check for this.
+               /*
+                * don't know how to accurately check for this.
                 * just assume it was a watchdog timer interrupt
                 * This matches the old behaviour.
                 */
@@ -396,7 +454,7 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
        char buf[64];
 
        sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-       die_nmi(regs, buf);
+       die_nmi(buf, regs, 1); /* Always panic here */
        return 0;
 }
 
@@ -414,32 +472,26 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
        if (!!old_state == !!nmi_watchdog_enabled)
                return 0;
 
-       if (atomic_read(&nmi_active) < 0 || nmi_watchdog == NMI_DISABLED) {
-               printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
+       if (atomic_read(&nmi_active) < 0 || !nmi_watchdog_active()) {
+               printk(KERN_WARNING
+                       "NMI watchdog is permanently disabled\n");
                return -EIO;
        }
 
-       if (nmi_watchdog == NMI_DEFAULT) {
-               if (lapic_watchdog_ok())
-                       nmi_watchdog = NMI_LOCAL_APIC;
-               else
-                       nmi_watchdog = NMI_IO_APIC;
-       }
-
        if (nmi_watchdog == NMI_LOCAL_APIC) {
                if (nmi_watchdog_enabled)
                        enable_lapic_nmi_watchdog();
                else
                        disable_lapic_nmi_watchdog();
        } else {
-               printk( KERN_WARNING
+               printk(KERN_WARNING
                        "NMI watchdog doesn't know what hardware to touch\n");
                return -EIO;
        }
        return 0;
 }
 
-#endif
+#endif /* CONFIG_SYSCTL */
 
 int do_nmi_callback(struct pt_regs *regs, int cpu)
 {
@@ -462,6 +514,3 @@ void __trigger_all_cpu_backtrace(void)
                mdelay(1);
        }
 }
-
-EXPORT_SYMBOL(nmi_active);
-EXPORT_SYMBOL(nmi_watchdog);
diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c
deleted file mode 100644 (file)
index 5a29ded..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- *  NMI watchdog support on APIC systems
- *
- *  Started by Ingo Molnar <mingo@redhat.com>
- *
- *  Fixes:
- *  Mikael Pettersson  : AMD K7 support for local APIC NMI watchdog.
- *  Mikael Pettersson  : Power Management for local APIC NMI watchdog.
- *  Pavel Machek and
- *  Mikael Pettersson  : PM converted to driver model. Disable/enable API.
- */
-
-#include <linux/nmi.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/sysdev.h>
-#include <linux/sysctl.h>
-#include <linux/kprobes.h>
-#include <linux/cpumask.h>
-#include <linux/kdebug.h>
-
-#include <asm/smp.h>
-#include <asm/nmi.h>
-#include <asm/proto.h>
-#include <asm/mce.h>
-
-#include <mach_traps.h>
-
-int unknown_nmi_panic;
-int nmi_watchdog_enabled;
-int panic_on_unrecovered_nmi;
-
-static cpumask_t backtrace_mask = CPU_MASK_NONE;
-
-/* nmi_active:
- * >0: the lapic NMI watchdog is active, but can be disabled
- * <0: the lapic NMI watchdog has not been set up, and cannot
- *     be enabled
- *  0: the lapic NMI watchdog is disabled, but can be enabled
- */
-atomic_t nmi_active = ATOMIC_INIT(0);          /* oprofile uses this */
-static int panic_on_timeout;
-
-unsigned int nmi_watchdog = NMI_DEFAULT;
-static unsigned int nmi_hz = HZ;
-
-static DEFINE_PER_CPU(short, wd_enabled);
-
-/* Run after command line and cpu_init init, but before all other checks */
-void nmi_watchdog_default(void)
-{
-       if (nmi_watchdog != NMI_DEFAULT)
-               return;
-       nmi_watchdog = NMI_NONE;
-}
-
-static int endflag __initdata = 0;
-
-#ifdef CONFIG_SMP
-/* The performance counters used by NMI_LOCAL_APIC don't trigger when
- * the CPU is idle. To make sure the NMI watchdog really ticks on all
- * CPUs during the test make them busy.
- */
-static __init void nmi_cpu_busy(void *data)
-{
-       local_irq_enable_in_hardirq();
-       /* Intentionally don't use cpu_relax here. This is
-          to make sure that the performance counter really ticks,
-          even if there is a simulator or similar that catches the
-          pause instruction. On a real HT machine this is fine because
-          all other CPUs are busy with "useless" delay loops and don't
-          care if they get somewhat less cycles. */
-       while (endflag == 0)
-               mb();
-}
-#endif
-
-int __init check_nmi_watchdog(void)
-{
-       int *prev_nmi_count;
-       int cpu;
-
-       if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DISABLED))
-               return 0;
-
-       if (!atomic_read(&nmi_active))
-               return 0;
-
-       prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL);
-       if (!prev_nmi_count)
-               return -1;
-
-       printk(KERN_INFO "Testing NMI watchdog ... ");
-
-#ifdef CONFIG_SMP
-       if (nmi_watchdog == NMI_LOCAL_APIC)
-               smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
-#endif
-
-       for (cpu = 0; cpu < NR_CPUS; cpu++)
-               prev_nmi_count[cpu] = cpu_pda(cpu)->__nmi_count;
-       local_irq_enable();
-       mdelay((20*1000)/nmi_hz); // wait 20 ticks
-
-       for_each_online_cpu(cpu) {
-               if (!per_cpu(wd_enabled, cpu))
-                       continue;
-               if (cpu_pda(cpu)->__nmi_count - prev_nmi_count[cpu] <= 5) {
-                       printk(KERN_WARNING "WARNING: CPU#%d: NMI "
-                              "appears to be stuck (%d->%d)!\n",
-                               cpu,
-                               prev_nmi_count[cpu],
-                               cpu_pda(cpu)->__nmi_count);
-                       per_cpu(wd_enabled, cpu) = 0;
-                       atomic_dec(&nmi_active);
-               }
-       }
-       endflag = 1;
-       if (!atomic_read(&nmi_active)) {
-               kfree(prev_nmi_count);
-               atomic_set(&nmi_active, -1);
-               return -1;
-       }
-       printk("OK.\n");
-
-       /* now that we know it works we can reduce NMI frequency to
-          something more reasonable; makes a difference in some configs */
-       if (nmi_watchdog == NMI_LOCAL_APIC)
-               nmi_hz = lapic_adjust_nmi_hz(1);
-
-       kfree(prev_nmi_count);
-       return 0;
-}
-
-static int __init setup_nmi_watchdog(char *str)
-{
-       int nmi;
-
-       if (!strncmp(str,"panic",5)) {
-               panic_on_timeout = 1;
-               str = strchr(str, ',');
-               if (!str)
-                       return 1;
-               ++str;
-       }
-
-       get_option(&str, &nmi);
-
-       if ((nmi >= NMI_INVALID) || (nmi < NMI_NONE))
-               return 0;
-
-       nmi_watchdog = nmi;
-       return 1;
-}
-
-__setup("nmi_watchdog=", setup_nmi_watchdog);
-
-#ifdef CONFIG_PM
-
-static int nmi_pm_active; /* nmi_active before suspend */
-
-static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
-{
-       /* only CPU0 goes here, other CPUs should be offline */
-       nmi_pm_active = atomic_read(&nmi_active);
-       stop_apic_nmi_watchdog(NULL);
-       BUG_ON(atomic_read(&nmi_active) != 0);
-       return 0;
-}
-
-static int lapic_nmi_resume(struct sys_device *dev)
-{
-       /* only CPU0 goes here, other CPUs should be offline */
-       if (nmi_pm_active > 0) {
-               setup_apic_nmi_watchdog(NULL);
-               touch_nmi_watchdog();
-       }
-       return 0;
-}
-
-static struct sysdev_class nmi_sysclass = {
-       .name           = "lapic_nmi",
-       .resume         = lapic_nmi_resume,
-       .suspend        = lapic_nmi_suspend,
-};
-
-static struct sys_device device_lapic_nmi = {
-       .id     = 0,
-       .cls    = &nmi_sysclass,
-};
-
-static int __init init_lapic_nmi_sysfs(void)
-{
-       int error;
-
-       /* should really be a BUG_ON but b/c this is an
-        * init call, it just doesn't work.  -dcz
-        */
-       if (nmi_watchdog != NMI_LOCAL_APIC)
-               return 0;
-
-       if (atomic_read(&nmi_active) < 0)
-               return 0;
-
-       error = sysdev_class_register(&nmi_sysclass);
-       if (!error)
-               error = sysdev_register(&device_lapic_nmi);
-       return error;
-}
-/* must come after the local APIC's device_initcall() */
-late_initcall(init_lapic_nmi_sysfs);
-
-#endif /* CONFIG_PM */
-
-static void __acpi_nmi_enable(void *__unused)
-{
-       apic_write(APIC_LVT0, APIC_DM_NMI);
-}
-
-/*
- * Enable timer based NMIs on all CPUs:
- */
-void acpi_nmi_enable(void)
-{
-       if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-               on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
-}
-
-static void __acpi_nmi_disable(void *__unused)
-{
-       apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
-}
-
-/*
- * Disable timer based NMIs on all CPUs:
- */
-void acpi_nmi_disable(void)
-{
-       if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-               on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
-}
-
-void setup_apic_nmi_watchdog(void *unused)
-{
-       if (__get_cpu_var(wd_enabled))
-               return;
-
-       /* cheap hack to support suspend/resume */
-       /* if cpu0 is not active neither should the other cpus */
-       if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
-               return;
-
-       switch (nmi_watchdog) {
-       case NMI_LOCAL_APIC:
-               __get_cpu_var(wd_enabled) = 1;
-               if (lapic_watchdog_init(nmi_hz) < 0) {
-                       __get_cpu_var(wd_enabled) = 0;
-                       return;
-               }
-               /* FALL THROUGH */
-       case NMI_IO_APIC:
-               __get_cpu_var(wd_enabled) = 1;
-               atomic_inc(&nmi_active);
-       }
-}
-
-void stop_apic_nmi_watchdog(void *unused)
-{
-       /* only support LOCAL and IO APICs for now */
-       if ((nmi_watchdog != NMI_LOCAL_APIC) &&
-           (nmi_watchdog != NMI_IO_APIC))
-               return;
-       if (__get_cpu_var(wd_enabled) == 0)
-               return;
-       if (nmi_watchdog == NMI_LOCAL_APIC)
-               lapic_watchdog_stop();
-       __get_cpu_var(wd_enabled) = 0;
-       atomic_dec(&nmi_active);
-}
-
-/*
- * the best way to detect whether a CPU has a 'hard lockup' problem
- * is to check it's local APIC timer IRQ counts. If they are not
- * changing then that CPU has some problem.
- *
- * as these watchdog NMI IRQs are generated on every CPU, we only
- * have to check the current processor.
- */
-
-static DEFINE_PER_CPU(unsigned, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
-static DEFINE_PER_CPU(int, nmi_touch);
-
-void touch_nmi_watchdog(void)
-{
-       if (nmi_watchdog > 0) {
-               unsigned cpu;
-
-               /*
-                * Tell other CPUs to reset their alert counters. We cannot
-                * do it ourselves because the alert count increase is not
-                * atomic.
-                */
-               for_each_present_cpu(cpu) {
-                       if (per_cpu(nmi_touch, cpu) != 1)
-                               per_cpu(nmi_touch, cpu) = 1;
-               }
-       }
-
-       touch_softlockup_watchdog();
-}
-EXPORT_SYMBOL(touch_nmi_watchdog);
-
-notrace __kprobes int
-nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
-{
-       int sum;
-       int touched = 0;
-       int cpu = smp_processor_id();
-       int rc = 0;
-
-       /* check for other users first */
-       if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
-                       == NOTIFY_STOP) {
-               rc = 1;
-               touched = 1;
-       }
-
-       sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
-       if (__get_cpu_var(nmi_touch)) {
-               __get_cpu_var(nmi_touch) = 0;
-               touched = 1;
-       }
-
-       if (cpu_isset(cpu, backtrace_mask)) {
-               static DEFINE_SPINLOCK(lock);   /* Serialise the printks */
-
-               spin_lock(&lock);
-               printk("NMI backtrace for cpu %d\n", cpu);
-               dump_stack();
-               spin_unlock(&lock);
-               cpu_clear(cpu, backtrace_mask);
-       }
-
-#ifdef CONFIG_X86_MCE
-       /* Could check oops_in_progress here too, but it's safer
-          not too */
-       if (atomic_read(&mce_entry) > 0)
-               touched = 1;
-#endif
-       /* if the apic timer isn't firing, this cpu isn't doing much */
-       if (!touched && __get_cpu_var(last_irq_sum) == sum) {
-               /*
-                * Ayiee, looks like this CPU is stuck ...
-                * wait a few IRQs (5 seconds) before doing the oops ...
-                */
-               local_inc(&__get_cpu_var(alert_counter));
-               if (local_read(&__get_cpu_var(alert_counter)) == 5*nmi_hz)
-                       die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs,
-                               panic_on_timeout);
-       } else {
-               __get_cpu_var(last_irq_sum) = sum;
-               local_set(&__get_cpu_var(alert_counter), 0);
-       }
-
-       /* see if the nmi watchdog went off */
-       if (!__get_cpu_var(wd_enabled))
-               return rc;
-       switch (nmi_watchdog) {
-       case NMI_LOCAL_APIC:
-               rc |= lapic_wd_event(nmi_hz);
-               break;
-       case NMI_IO_APIC:
-               /* don't know how to accurately check for this.
-                * just assume it was a watchdog timer interrupt
-                * This matches the old behaviour.
-                */
-               rc = 1;
-               break;
-       }
-       return rc;
-}
-
-static unsigned ignore_nmis;
-
-asmlinkage notrace __kprobes void
-do_nmi(struct pt_regs *regs, long error_code)
-{
-       nmi_enter();
-       add_pda(__nmi_count,1);
-       if (!ignore_nmis)
-               default_do_nmi(regs);
-       nmi_exit();
-}
-
-void stop_nmi(void)
-{
-       acpi_nmi_disable();
-       ignore_nmis++;
-}
-
-void restart_nmi(void)
-{
-       ignore_nmis--;
-       acpi_nmi_enable();
-}
-
-#ifdef CONFIG_SYSCTL
-
-static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
-{
-       unsigned char reason = get_nmi_reason();
-       char buf[64];
-
-       sprintf(buf, "NMI received for unknown reason %02x\n", reason);
-       die_nmi(buf, regs, 1);  /* Always panic here */
-       return 0;
-}
-
-/*
- * proc handler for /proc/sys/kernel/nmi
- */
-int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
-                       void __user *buffer, size_t *length, loff_t *ppos)
-{
-       int old_state;
-
-       nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
-       old_state = nmi_watchdog_enabled;
-       proc_dointvec(table, write, file, buffer, length, ppos);
-       if (!!old_state == !!nmi_watchdog_enabled)
-               return 0;
-
-       if (atomic_read(&nmi_active) < 0 || nmi_watchdog == NMI_DISABLED) {
-               printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
-               return -EIO;
-       }
-
-       /* if nmi_watchdog is not set yet, then set it */
-       nmi_watchdog_default();
-
-       if (nmi_watchdog == NMI_LOCAL_APIC) {
-               if (nmi_watchdog_enabled)
-                       enable_lapic_nmi_watchdog();
-               else
-                       disable_lapic_nmi_watchdog();
-       } else {
-               printk( KERN_WARNING
-                       "NMI watchdog doesn't know what hardware to touch\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-#endif
-
-int do_nmi_callback(struct pt_regs *regs, int cpu)
-{
-#ifdef CONFIG_SYSCTL
-       if (unknown_nmi_panic)
-               return unknown_nmi_panic_callback(regs, cpu);
-#endif
-       return 0;
-}
-
-void __trigger_all_cpu_backtrace(void)
-{
-       int i;
-
-       backtrace_mask = cpu_online_map;
-       /* Wait for up to 10 seconds for all CPUs to do the backtrace */
-       for (i = 0; i < 10 * 1000; i++) {
-               if (cpus_empty(backtrace_mask))
-                       break;
-               mdelay(1);
-       }
-}
-
-EXPORT_SYMBOL(nmi_active);
-EXPORT_SYMBOL(nmi_watchdog);
index e65281b1634b790bd151c479fc96f3846febe87d..5b20a5e7ac28933e8200c269880cc167603cafeb 100644 (file)
@@ -31,6 +31,8 @@
 #include <asm/numaq.h>
 #include <asm/topology.h>
 #include <asm/processor.h>
+#include <asm/mpspec.h>
+#include <asm/e820.h>
 
 #define        MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
 
@@ -58,6 +60,8 @@ static void __init smp_dump_qct(void)
                        node_end_pfn[node] = MB_TO_PAGES(
                                eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
 
+                       e820_register_active_regions(node, node_start_pfn[node],
+                                                       node_end_pfn[node]);
                        memory_present(node,
                                node_start_pfn[node], node_end_pfn[node]);
                        node_remap_size[node] = node_memmap_size_bytes(node,
@@ -67,23 +71,35 @@ static void __init smp_dump_qct(void)
        }
 }
 
-/*
- * Unlike Summit, we don't really care to let the NUMA-Q
- * fall back to flat mode.  Don't compile for NUMA-Q
- * unless you really need it!
- */
+static __init void early_check_numaq(void)
+{
+       /*
+        * Find possible boot-time SMP configuration:
+        */
+       early_find_smp_config();
+       /*
+        * get boot-time SMP configuration:
+        */
+       if (smp_found_config)
+               early_get_smp_config();
+}
+
 int __init get_memcfg_numaq(void)
 {
+       early_check_numaq();
+       if (!found_numaq)
+               return 0;
        smp_dump_qct();
        return 1;
 }
 
-static int __init numaq_tsc_disable(void)
+void __init numaq_tsc_disable(void)
 {
+       if (!found_numaq)
+               return -1;
+
        if (num_online_nodes() > 1) {
                printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
                setup_clear_cpu_cap(X86_FEATURE_TSC);
        }
-       return 0;
 }
-arch_initcall(numaq_tsc_disable);
index 74f0c5ea2a0388af848faa058804cd9df86f4391..e0f571d58c19c0bfa4eeee39d89972ed2239f55f 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/setup.h>
 #include <asm/arch_hooks.h>
 #include <asm/time.h>
+#include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 #include <asm/fixmap.h>
@@ -139,7 +140,9 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
                /* If the operation is a nop, then nop the callsite */
                ret = paravirt_patch_nop();
        else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
-                type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_syscall_ret))
+                type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
+                type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
+                type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
                /* If operation requires a jmp, then jmp */
                ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
        else
@@ -190,7 +193,9 @@ static void native_flush_tlb_single(unsigned long addr)
 
 /* These are in entry.S */
 extern void native_iret(void);
-extern void native_irq_enable_syscall_ret(void);
+extern void native_irq_enable_sysexit(void);
+extern void native_usergs_sysret32(void);
+extern void native_usergs_sysret64(void);
 
 static int __init print_banner(void)
 {
@@ -280,7 +285,7 @@ struct pv_time_ops pv_time_ops = {
        .get_wallclock = native_get_wallclock,
        .set_wallclock = native_set_wallclock,
        .sched_clock = native_sched_clock,
-       .get_cpu_khz = native_calculate_cpu_khz,
+       .get_tsc_khz = native_calibrate_tsc,
 };
 
 struct pv_irq_ops pv_irq_ops = {
@@ -291,6 +296,9 @@ struct pv_irq_ops pv_irq_ops = {
        .irq_enable = native_irq_enable,
        .safe_halt = native_safe_halt,
        .halt = native_halt,
+#ifdef CONFIG_X86_64
+       .adjust_exception_frame = paravirt_nop,
+#endif
 };
 
 struct pv_cpu_ops pv_cpu_ops = {
@@ -321,12 +329,23 @@ struct pv_cpu_ops pv_cpu_ops = {
        .store_idt = native_store_idt,
        .store_tr = native_store_tr,
        .load_tls = native_load_tls,
+#ifdef CONFIG_X86_64
+       .load_gs_index = native_load_gs_index,
+#endif
        .write_ldt_entry = native_write_ldt_entry,
        .write_gdt_entry = native_write_gdt_entry,
        .write_idt_entry = native_write_idt_entry,
        .load_sp0 = native_load_sp0,
 
-       .irq_enable_syscall_ret = native_irq_enable_syscall_ret,
+#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
+       .irq_enable_sysexit = native_irq_enable_sysexit,
+#endif
+#ifdef CONFIG_X86_64
+#ifdef CONFIG_IA32_EMULATION
+       .usergs_sysret32 = native_usergs_sysret32,
+#endif
+       .usergs_sysret64 = native_usergs_sysret64,
+#endif
        .iret = native_iret,
        .swapgs = native_swapgs,
 
@@ -366,6 +385,9 @@ struct pv_mmu_ops pv_mmu_ops = {
        .flush_tlb_single = native_flush_tlb_single,
        .flush_tlb_others = native_flush_tlb_others,
 
+       .pgd_alloc = __paravirt_pgd_alloc,
+       .pgd_free = paravirt_nop,
+
        .alloc_pte = paravirt_nop,
        .alloc_pmd = paravirt_nop,
        .alloc_pmd_clone = paravirt_nop,
@@ -380,6 +402,9 @@ struct pv_mmu_ops pv_mmu_ops = {
        .pte_update = paravirt_nop,
        .pte_update_defer = paravirt_nop,
 
+       .ptep_modify_prot_start = __ptep_modify_prot_start,
+       .ptep_modify_prot_commit = __ptep_modify_prot_commit,
+
 #ifdef CONFIG_HIGHPTE
        .kmap_atomic_pte = kmap_atomic,
 #endif
@@ -403,6 +428,7 @@ struct pv_mmu_ops pv_mmu_ops = {
 #endif /* PAGETABLE_LEVELS >= 3 */
 
        .pte_val = native_pte_val,
+       .pte_flags = native_pte_val,
        .pgd_val = native_pgd_val,
 
        .make_pte = native_make_pte,
@@ -416,6 +442,8 @@ struct pv_mmu_ops pv_mmu_ops = {
                .enter = paravirt_nop,
                .leave = paravirt_nop,
        },
+
+       .set_fixmap = native_set_fixmap,
 };
 
 EXPORT_SYMBOL_GPL(pv_time_ops);
index 82fc5fcab4f4eb7cba501db2e7d6a9a89d027020..58262218781bd3582b1b99f7d42986170e49e23c 100644 (file)
@@ -5,7 +5,7 @@ DEF_NATIVE(pv_irq_ops, irq_enable, "sti");
 DEF_NATIVE(pv_irq_ops, restore_fl, "push %eax; popf");
 DEF_NATIVE(pv_irq_ops, save_fl, "pushf; pop %eax");
 DEF_NATIVE(pv_cpu_ops, iret, "iret");
-DEF_NATIVE(pv_cpu_ops, irq_enable_syscall_ret, "sti; sysexit");
+DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "sti; sysexit");
 DEF_NATIVE(pv_mmu_ops, read_cr2, "mov %cr2, %eax");
 DEF_NATIVE(pv_mmu_ops, write_cr3, "mov %eax, %cr3");
 DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
@@ -29,7 +29,7 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
                PATCH_SITE(pv_irq_ops, restore_fl);
                PATCH_SITE(pv_irq_ops, save_fl);
                PATCH_SITE(pv_cpu_ops, iret);
-               PATCH_SITE(pv_cpu_ops, irq_enable_syscall_ret);
+               PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
                PATCH_SITE(pv_mmu_ops, read_cr2);
                PATCH_SITE(pv_mmu_ops, read_cr3);
                PATCH_SITE(pv_mmu_ops, write_cr3);
index 7d904e138d7e482cc9bb83e67db1b9718273a576..061d01df9ae6aa0ff09ff17d43eab28e61d21b10 100644 (file)
@@ -14,8 +14,9 @@ DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
 DEF_NATIVE(pv_cpu_ops, clts, "clts");
 DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");
 
-/* the three commands give us more control to how to return from a syscall */
-DEF_NATIVE(pv_cpu_ops, irq_enable_syscall_ret, "movq %gs:" __stringify(pda_oldrsp) ", %rsp; swapgs; sysretq;");
+DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "swapgs; sti; sysexit");
+DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
+DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
 DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
 
 unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
@@ -35,7 +36,9 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
                PATCH_SITE(pv_irq_ops, irq_enable);
                PATCH_SITE(pv_irq_ops, irq_disable);
                PATCH_SITE(pv_cpu_ops, iret);
-               PATCH_SITE(pv_cpu_ops, irq_enable_syscall_ret);
+               PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
+               PATCH_SITE(pv_cpu_ops, usergs_sysret32);
+               PATCH_SITE(pv_cpu_ops, usergs_sysret64);
                PATCH_SITE(pv_cpu_ops, swapgs);
                PATCH_SITE(pv_mmu_ops, read_cr2);
                PATCH_SITE(pv_mmu_ops, read_cr3);
index e28ec497e142f49cc4847f833ff5a5f8f96833f6..6959b5c45df4546f28c2ef962fdc197d7afbfe3a 100644 (file)
@@ -1394,7 +1394,7 @@ void __init detect_calgary(void)
                return;
        }
 
-       specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
+       specified_table_size = determine_tce_table_size(max_pfn * PAGE_SIZE);
 
        for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
                struct calgary_bus_info *info = &bus_info[bus];
@@ -1459,7 +1459,7 @@ int __init calgary_iommu_init(void)
        if (ret) {
                printk(KERN_ERR "PCI-DMA: Calgary init failed %d, "
                       "falling back to no_iommu\n", ret);
-               if (end_pfn > MAX_DMA32_PFN)
+               if (max_pfn > MAX_DMA32_PFN)
                        printk(KERN_ERR "WARNING more than 4GB of memory, "
                                        "32bit PCI may malfunction.\n");
                return ret;
index dc00a1331acef73c204ed0979d8527450af5246f..8467ec2320f178584afb402cfb2b48859a3eb48e 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/dma.h>
 #include <asm/gart.h>
 #include <asm/calgary.h>
+#include <asm/amd_iommu.h>
 
 int forbid_dac __read_mostly;
 EXPORT_SYMBOL(forbid_dac);
@@ -74,13 +75,17 @@ early_param("dma32_size", parse_dma32_size_opt);
 void __init dma32_reserve_bootmem(void)
 {
        unsigned long size, align;
-       if (end_pfn <= MAX_DMA32_PFN)
+       if (max_pfn <= MAX_DMA32_PFN)
                return;
 
+       /*
+        * check aperture_64.c allocate_aperture() for reason about
+        * using 512M as goal
+        */
        align = 64ULL<<20;
        size = round_up(dma32_bootmem_size, align);
        dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
-                                __pa(MAX_DMA_ADDRESS));
+                                512ULL<<20);
        if (dma32_bootmem_ptr)
                dma32_bootmem_size = size;
        else
@@ -88,17 +93,14 @@ void __init dma32_reserve_bootmem(void)
 }
 static void __init dma32_free_bootmem(void)
 {
-       int node;
 
-       if (end_pfn <= MAX_DMA32_PFN)
+       if (max_pfn <= MAX_DMA32_PFN)
                return;
 
        if (!dma32_bootmem_ptr)
                return;
 
-       for_each_online_node(node)
-               free_bootmem_node(NODE_DATA(node), __pa(dma32_bootmem_ptr),
-                                 dma32_bootmem_size);
+       free_bootmem(__pa(dma32_bootmem_ptr), dma32_bootmem_size);
 
        dma32_bootmem_ptr = NULL;
        dma32_bootmem_size = 0;
@@ -122,6 +124,8 @@ void __init pci_iommu_alloc(void)
 
        detect_intel_iommu();
 
+       amd_iommu_detect();
+
 #ifdef CONFIG_SWIOTLB
        pci_swiotlb_init();
 #endif
@@ -357,7 +361,7 @@ int dma_supported(struct device *dev, u64 mask)
 EXPORT_SYMBOL(dma_supported);
 
 /* Allocate DMA memory on node near device */
-noinline struct page *
+static noinline struct page *
 dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
 {
        int node;
@@ -502,6 +506,8 @@ static int __init pci_iommu_init(void)
 
        intel_iommu_init();
 
+       amd_iommu_init();
+
 #ifdef CONFIG_GART_IOMMU
        gart_iommu_init();
 #endif
index aa8ec928caa85ff43d4da3a0fe3e7d570b57f08a..c3fe78406d1897b40e380f0528cf4db832d0a191 100644 (file)
@@ -104,7 +104,6 @@ static unsigned long alloc_iommu(struct device *dev, int size)
                                          size, base_index, boundary_size, 0);
        }
        if (offset != -1) {
-               set_bit_string(iommu_gart_bitmap, offset, size);
                next_bit = offset+size;
                if (next_bit >= iommu_pages) {
                        next_bit = 0;
@@ -534,8 +533,8 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
        unsigned aper_size = 0, aper_base_32, aper_order;
        u64 aper_base;
 
-       pci_read_config_dword(dev, 0x94, &aper_base_32);
-       pci_read_config_dword(dev, 0x90, &aper_order);
+       pci_read_config_dword(dev, AMD64_GARTAPERTUREBASE, &aper_base_32);
+       pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &aper_order);
        aper_order = (aper_order >> 1) & 7;
 
        aper_base = aper_base_32 & 0x7fff;
@@ -549,14 +548,63 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size)
        return aper_base;
 }
 
+static void enable_gart_translations(void)
+{
+       int i;
+
+       for (i = 0; i < num_k8_northbridges; i++) {
+               struct pci_dev *dev = k8_northbridges[i];
+
+               enable_gart_translation(dev, __pa(agp_gatt_table));
+       }
+}
+
+/*
+ * If fix_up_north_bridges is set, the north bridges have to be fixed up on
+ * resume in the same way as they are handled in gart_iommu_hole_init().
+ */
+static bool fix_up_north_bridges;
+static u32 aperture_order;
+static u32 aperture_alloc;
+
+void set_up_gart_resume(u32 aper_order, u32 aper_alloc)
+{
+       fix_up_north_bridges = true;
+       aperture_order = aper_order;
+       aperture_alloc = aper_alloc;
+}
+
 static int gart_resume(struct sys_device *dev)
 {
+       printk(KERN_INFO "PCI-DMA: Resuming GART IOMMU\n");
+
+       if (fix_up_north_bridges) {
+               int i;
+
+               printk(KERN_INFO "PCI-DMA: Restoring GART aperture settings\n");
+
+               for (i = 0; i < num_k8_northbridges; i++) {
+                       struct pci_dev *dev = k8_northbridges[i];
+
+                       /*
+                        * Don't enable translations just yet.  That is the next
+                        * step.  Restore the pre-suspend aperture settings.
+                        */
+                       pci_write_config_dword(dev, AMD64_GARTAPERTURECTL,
+                                               aperture_order << 1);
+                       pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE,
+                                               aperture_alloc >> 25);
+               }
+       }
+
+       enable_gart_translations();
+
        return 0;
 }
 
 static int gart_suspend(struct sys_device *dev, pm_message_t state)
 {
-       return -EINVAL;
+       return 0;
 }
 
 static struct sysdev_class gart_sysdev_class = {
@@ -582,6 +630,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
        struct pci_dev *dev;
        void *gatt;
        int i, error;
+       unsigned long start_pfn, end_pfn;
 
        printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
        aper_size = aper_base = info->aper_size = 0;
@@ -614,31 +663,25 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
        memset(gatt, 0, gatt_size);
        agp_gatt_table = gatt;
 
-       for (i = 0; i < num_k8_northbridges; i++) {
-               u32 gatt_reg;
-               u32 ctl;
-
-               dev = k8_northbridges[i];
-               gatt_reg = __pa(gatt) >> 12;
-               gatt_reg <<= 4;
-               pci_write_config_dword(dev, 0x98, gatt_reg);
-               pci_read_config_dword(dev, 0x90, &ctl);
-
-               ctl |= 1;
-               ctl &= ~((1<<4) | (1<<5));
-
-               pci_write_config_dword(dev, 0x90, ctl);
-       }
+       enable_gart_translations();
 
        error = sysdev_class_register(&gart_sysdev_class);
        if (!error)
                error = sysdev_register(&device_gart);
        if (error)
                panic("Could not register gart_sysdev -- would corrupt data on next suspend");
+
        flush_gart();
 
        printk(KERN_INFO "PCI-DMA: aperture base @ %x size %u KB\n",
               aper_base, aper_size>>10);
+
+       /* need to map that range */
+       end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT);
+       if (end_pfn > max_low_pfn_mapped) {
+               start_pfn = (aper_base>>PAGE_SHIFT);
+               init_memory_mapping(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+       }
        return 0;
 
  nommu:
@@ -677,11 +720,11 @@ void gart_iommu_shutdown(void)
                u32 ctl;
 
                dev = k8_northbridges[i];
-               pci_read_config_dword(dev, 0x90, &ctl);
+               pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
 
-               ctl &= ~1;
+               ctl &= ~GARTEN;
 
-               pci_write_config_dword(dev, 0x90, ctl);
+               pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
        }
 }
 
@@ -716,10 +759,10 @@ void __init gart_iommu_init(void)
                return;
 
        if (no_iommu ||
-           (!force_iommu && end_pfn <= MAX_DMA32_PFN) ||
+           (!force_iommu && max_pfn <= MAX_DMA32_PFN) ||
            !gart_iommu_aperture ||
            (no_agp && init_k8_gatt(&info) < 0)) {
-               if (end_pfn > MAX_DMA32_PFN) {
+               if (max_pfn > MAX_DMA32_PFN) {
                        printk(KERN_WARNING "More than 4GB of memory "
                                          "but GART IOMMU not available.\n"
                               KERN_WARNING "falling back to iommu=soft.\n");
@@ -788,10 +831,10 @@ void __init gart_iommu_init(void)
        wbinvd();
 
        /*
-        * Try to workaround a bug (thanks to BenH)
+        * Try to workaround a bug (thanks to BenH):
         * Set unmapped entries to a scratch page instead of 0.
         * Any prefetches that hit unmapped entries won't get an bus abort
-        * then.
+        * then. (P2P bridge may be prefetching on DMA reads).
         */
        scratch = get_zeroed_page(GFP_KERNEL);
        if (!scratch)
index 490da7f4b8d0dd8e29abf7ddd2e11b01fe19f196..82299cd1d04d452fea6ba6069fb3297a8824f7de 100644 (file)
@@ -38,7 +38,7 @@ const struct dma_mapping_ops swiotlb_dma_ops = {
 void __init pci_swiotlb_init(void)
 {
        /* don't initialize swiotlb if iommu=off (no_iommu=1) */
-       if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN)
+       if (!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN)
               swiotlb = 1;
        if (swiotlb_force)
                swiotlb = 1;
diff --git a/arch/x86/kernel/probe_roms_32.c b/arch/x86/kernel/probe_roms_32.c
new file mode 100644 (file)
index 0000000..675a48c
--- /dev/null
@@ -0,0 +1,166 @@
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/mmzone.h>
+#include <linux/ioport.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/edd.h>
+#include <linux/dmi.h>
+#include <linux/pfn.h>
+#include <linux/pci.h>
+#include <asm/pci-direct.h>
+
+
+#include <asm/e820.h>
+#include <asm/mmzone.h>
+#include <asm/setup.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <setup_arch.h>
+
+static struct resource system_rom_resource = {
+       .name   = "System ROM",
+       .start  = 0xf0000,
+       .end    = 0xfffff,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource extension_rom_resource = {
+       .name   = "Extension ROM",
+       .start  = 0xe0000,
+       .end    = 0xeffff,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource adapter_rom_resources[] = { {
+       .name   = "Adapter ROM",
+       .start  = 0xc8000,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+       .name   = "Adapter ROM",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+       .name   = "Adapter ROM",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+       .name   = "Adapter ROM",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+       .name   = "Adapter ROM",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+       .name   = "Adapter ROM",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+} };
+
+static struct resource video_rom_resource = {
+       .name   = "Video ROM",
+       .start  = 0xc0000,
+       .end    = 0xc7fff,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+#define ROMSIGNATURE 0xaa55
+
+static int __init romsignature(const unsigned char *rom)
+{
+       const unsigned short * const ptr = (const unsigned short *)rom;
+       unsigned short sig;
+
+       return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE;
+}
+
+static int __init romchecksum(const unsigned char *rom, unsigned long length)
+{
+       unsigned char sum, c;
+
+       for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--)
+               sum += c;
+       return !length && !sum;
+}
+
+void __init probe_roms(void)
+{
+       const unsigned char *rom;
+       unsigned long start, length, upper;
+       unsigned char c;
+       int i;
+
+       /* video rom */
+       upper = adapter_rom_resources[0].start;
+       for (start = video_rom_resource.start; start < upper; start += 2048) {
+               rom = isa_bus_to_virt(start);
+               if (!romsignature(rom))
+                       continue;
+
+               video_rom_resource.start = start;
+
+               if (probe_kernel_address(rom + 2, c) != 0)
+                       continue;
+
+               /* 0 < length <= 0x7f * 512, historically */
+               length = c * 512;
+
+               /* if checksum okay, trust length byte */
+               if (length && romchecksum(rom, length))
+                       video_rom_resource.end = start + length - 1;
+
+               request_resource(&iomem_resource, &video_rom_resource);
+               break;
+       }
+
+       start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
+       if (start < upper)
+               start = upper;
+
+       /* system rom */
+       request_resource(&iomem_resource, &system_rom_resource);
+       upper = system_rom_resource.start;
+
+       /* check for extension rom (ignore length byte!) */
+       rom = isa_bus_to_virt(extension_rom_resource.start);
+       if (romsignature(rom)) {
+               length = extension_rom_resource.end - extension_rom_resource.start + 1;
+               if (romchecksum(rom, length)) {
+                       request_resource(&iomem_resource, &extension_rom_resource);
+                       upper = extension_rom_resource.start;
+               }
+       }
+
+       /* check for adapter roms on 2k boundaries */
+       for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
+               rom = isa_bus_to_virt(start);
+               if (!romsignature(rom))
+                       continue;
+
+               if (probe_kernel_address(rom + 2, c) != 0)
+                       continue;
+
+               /* 0 < length <= 0x7f * 512, historically */
+               length = c * 512;
+
+               /* but accept any length that fits if checksum okay */
+               if (!length || start + length > upper || !romchecksum(rom, length))
+                       continue;
+
+               adapter_rom_resources[i].start = start;
+               adapter_rom_resources[i].end = start + length - 1;
+               request_resource(&iomem_resource, &adapter_rom_resources[i]);
+
+               start = adapter_rom_resources[i++].end & ~2047UL;
+       }
+}
+
index ba370dc8685bf8f9bf31e9100f78c4e800ea755e..4061d63aabe74bb12f32f5d162c564240ae8d8a5 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/pm.h>
+#include <linux/clockchips.h>
 
 struct kmem_cache *task_xstate_cachep;
 
@@ -45,6 +46,76 @@ void arch_task_cache_init(void)
                                  SLAB_PANIC, NULL);
 }
 
+/*
+ * Idle related variables and functions
+ */
+unsigned long boot_option_idle_override = 0;
+EXPORT_SYMBOL(boot_option_idle_override);
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void);
+EXPORT_SYMBOL(pm_idle);
+
+#ifdef CONFIG_X86_32
+/*
+ * This halt magic was a workaround for ancient floppy DMA
+ * wreckage. It should be safe to remove.
+ */
+static int hlt_counter;
+void disable_hlt(void)
+{
+       hlt_counter++;
+}
+EXPORT_SYMBOL(disable_hlt);
+
+void enable_hlt(void)
+{
+       hlt_counter--;
+}
+EXPORT_SYMBOL(enable_hlt);
+
+static inline int hlt_use_halt(void)
+{
+       return (!hlt_counter && boot_cpu_data.hlt_works_ok);
+}
+#else
+static inline int hlt_use_halt(void)
+{
+       return 1;
+}
+#endif
+
+/*
+ * We use this if we don't have any better
+ * idle routine..
+ */
+void default_idle(void)
+{
+       if (hlt_use_halt()) {
+               current_thread_info()->status &= ~TS_POLLING;
+               /*
+                * TS_POLLING-cleared state must be visible before we
+                * test NEED_RESCHED:
+                */
+               smp_mb();
+
+               if (!need_resched())
+                       safe_halt();    /* enables interrupts racelessly */
+               else
+                       local_irq_enable();
+               current_thread_info()->status |= TS_POLLING;
+       } else {
+               local_irq_enable();
+               /* loop is done by the caller */
+               cpu_relax();
+       }
+}
+#ifdef CONFIG_APM_MODULE
+EXPORT_SYMBOL(default_idle);
+#endif
+
 static void do_nothing(void *unused)
 {
 }
@@ -122,44 +193,129 @@ static void poll_idle(void)
  *
  * idle=mwait overrides this decision and forces the usage of mwait.
  */
+
+#define MWAIT_INFO                     0x05
+#define MWAIT_ECX_EXTENDED_INFO                0x01
+#define MWAIT_EDX_C1                   0xf0
+
 static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
 {
+       u32 eax, ebx, ecx, edx;
+
        if (force_mwait)
                return 1;
 
-       if (c->x86_vendor == X86_VENDOR_AMD) {
-               switch(c->x86) {
-               case 0x10:
-               case 0x11:
-                       return 0;
-               }
-       }
+       if (c->cpuid_level < MWAIT_INFO)
+               return 0;
+
+       cpuid(MWAIT_INFO, &eax, &ebx, &ecx, &edx);
+       /* Check, whether EDX has extended info about MWAIT */
+       if (!(ecx & MWAIT_ECX_EXTENDED_INFO))
+               return 1;
+
+       /*
+        * edx enumeratios MONITOR/MWAIT extensions. Check, whether
+        * C1  supports MWAIT
+        */
+       return (edx & MWAIT_EDX_C1);
+}
+
+/*
+ * Check for AMD CPUs, which have potentially C1E support
+ */
+static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)
+{
+       if (c->x86_vendor != X86_VENDOR_AMD)
+               return 0;
+
+       if (c->x86 < 0x0F)
+               return 0;
+
+       /* Family 0x0f models < rev F do not have C1E */
+       if (c->x86 == 0x0f && c->x86_model < 0x40)
+               return 0;
+
        return 1;
 }
 
-void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
+/*
+ * C1E aware idle routine. We check for C1E active in the interrupt
+ * pending message MSR. If we detect C1E, then we handle it the same
+ * way as C3 power states (local apic timer and TSC stop)
+ */
+static void c1e_idle(void)
 {
-       static int selected;
+       static cpumask_t c1e_mask = CPU_MASK_NONE;
+       static int c1e_detected;
 
-       if (selected)
+       if (need_resched())
                return;
+
+       if (!c1e_detected) {
+               u32 lo, hi;
+
+               rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
+               if (lo & K8_INTP_C1E_ACTIVE_MASK) {
+                       c1e_detected = 1;
+                       mark_tsc_unstable("TSC halt in C1E");
+                       printk(KERN_INFO "System has C1E enabled\n");
+               }
+       }
+
+       if (c1e_detected) {
+               int cpu = smp_processor_id();
+
+               if (!cpu_isset(cpu, c1e_mask)) {
+                       cpu_set(cpu, c1e_mask);
+                       /*
+                        * Force broadcast so ACPI can not interfere. Needs
+                        * to run with interrupts enabled as it uses
+                        * smp_function_call.
+                        */
+                       local_irq_enable();
+                       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
+                                          &cpu);
+                       printk(KERN_INFO "Switch to broadcast mode on CPU%d\n",
+                              cpu);
+                       local_irq_disable();
+               }
+               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+               default_idle();
+
+               /*
+                * The switch back from broadcast mode needs to be
+                * called with interrupts disabled.
+                */
+                local_irq_disable();
+                clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+                local_irq_enable();
+       } else
+               default_idle();
+}
+
+void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
+{
 #ifdef CONFIG_X86_SMP
        if (pm_idle == poll_idle && smp_num_siblings > 1) {
                printk(KERN_WARNING "WARNING: polling idle and HT enabled,"
                        " performance may degrade.\n");
        }
 #endif
+       if (pm_idle)
+               return;
+
        if (cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)) {
                /*
-                * Skip, if setup has overridden idle.
                 * One CPU supports mwait => All CPUs supports mwait
                 */
-               if (!pm_idle) {
-                       printk(KERN_INFO "using mwait in idle threads.\n");
-                       pm_idle = mwait_idle;
-               }
-       }
-       selected = 1;
+               printk(KERN_INFO "using mwait in idle threads.\n");
+               pm_idle = mwait_idle;
+       } else if (check_c1e_idle(c)) {
+               printk(KERN_INFO "using C1E aware idle routine\n");
+               pm_idle = c1e_idle;
+       } else
+               pm_idle = default_idle;
 }
 
 static int __init idle_setup(char *str)
index e2db9ac5c61c2b6d6de1f0b13f71b6d834eaeca2..9a139f6c9df30fa2c304e96da89b99fd62b78a8d 100644 (file)
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
-static int hlt_counter;
-
-unsigned long boot_option_idle_override = 0;
-EXPORT_SYMBOL(boot_option_idle_override);
-
 DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
 EXPORT_PER_CPU_SYMBOL(current_task);
 
@@ -77,57 +72,24 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
        return ((unsigned long *)tsk->thread.sp)[3];
 }
 
-/*
- * Powermanagement idle function, if any..
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
+#ifdef CONFIG_HOTPLUG_CPU
+#include <asm/nmi.h>
 
-void disable_hlt(void)
+static void cpu_exit_clear(void)
 {
-       hlt_counter++;
-}
+       int cpu = raw_smp_processor_id();
 
-EXPORT_SYMBOL(disable_hlt);
+       idle_task_exit();
 
-void enable_hlt(void)
-{
-       hlt_counter--;
-}
+       cpu_uninit();
+       irq_ctx_exit(cpu);
 
-EXPORT_SYMBOL(enable_hlt);
-
-/*
- * We use this if we don't have any better
- * idle routine..
- */
-void default_idle(void)
-{
-       if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
-               current_thread_info()->status &= ~TS_POLLING;
-               /*
-                * TS_POLLING-cleared state must be visible before we
-                * test NEED_RESCHED:
-                */
-               smp_mb();
+       cpu_clear(cpu, cpu_callout_map);
+       cpu_clear(cpu, cpu_callin_map);
 
-               if (!need_resched())
-                       safe_halt();    /* enables interrupts racelessly */
-               else
-                       local_irq_enable();
-               current_thread_info()->status |= TS_POLLING;
-       } else {
-               local_irq_enable();
-               /* loop is done by the caller */
-               cpu_relax();
-       }
+       numa_remove_cpu(cpu);
 }
-#ifdef CONFIG_APM_MODULE
-EXPORT_SYMBOL(default_idle);
-#endif
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
 /* We don't actually take CPU down, just spin without interrupts. */
 static inline void play_dead(void)
 {
@@ -168,24 +130,19 @@ void cpu_idle(void)
        while (1) {
                tick_nohz_stop_sched_tick();
                while (!need_resched()) {
-                       void (*idle)(void);
 
                        check_pgt_cache();
                        rmb();
-                       idle = pm_idle;
 
                        if (rcu_pending(cpu))
                                rcu_check_callbacks(cpu, 0);
 
-                       if (!idle)
-                               idle = default_idle;
-
                        if (cpu_is_offline(cpu))
                                play_dead();
 
                        local_irq_disable();
                        __get_cpu_var(irq_stat).idle_timestamp = jiffies;
-                       idle();
+                       pm_idle();
                }
                tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
index c6eb5c91e5f607f7fb70758ed65eee667c7d1401..db5eb963e4df2e7d573012f96bc3696eff6b52ca 100644 (file)
@@ -56,15 +56,6 @@ asmlinkage extern void ret_from_fork(void);
 
 unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
 
-unsigned long boot_option_idle_override = 0;
-EXPORT_SYMBOL(boot_option_idle_override);
-
-/*
- * Powermanagement idle function, if any..
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
-
 static ATOMIC_NOTIFIER_HEAD(idle_notifier);
 
 void idle_notifier_register(struct notifier_block *n)
@@ -94,25 +85,6 @@ void exit_idle(void)
        __exit_idle();
 }
 
-/*
- * We use this if we don't have any better
- * idle routine..
- */
-void default_idle(void)
-{
-       current_thread_info()->status &= ~TS_POLLING;
-       /*
-        * TS_POLLING-cleared state must be visible before we
-        * test NEED_RESCHED:
-        */
-       smp_mb();
-       if (!need_resched())
-               safe_halt();    /* enables interrupts racelessly */
-       else
-               local_irq_enable();
-       current_thread_info()->status |= TS_POLLING;
-}
-
 #ifdef CONFIG_HOTPLUG_CPU
 DECLARE_PER_CPU(int, cpu_state);
 
@@ -150,12 +122,9 @@ void cpu_idle(void)
        while (1) {
                tick_nohz_stop_sched_tick();
                while (!need_resched()) {
-                       void (*idle)(void);
 
                        rmb();
-                       idle = pm_idle;
-                       if (!idle)
-                               idle = default_idle;
+
                        if (cpu_is_offline(smp_processor_id()))
                                play_dead();
                        /*
@@ -165,7 +134,7 @@ void cpu_idle(void)
                         */
                        local_irq_disable();
                        enter_idle();
-                       idle();
+                       pm_idle();
                        /* In many cases the interrupt that ended idle
                           has already called exit_idle. But some idle
                           loops can be woken up without interrupt. */
@@ -366,10 +335,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        p->thread.fs = me->thread.fs;
        p->thread.gs = me->thread.gs;
 
-       asm("mov %%gs,%0" : "=m" (p->thread.gsindex));
-       asm("mov %%fs,%0" : "=m" (p->thread.fsindex));
-       asm("mov %%es,%0" : "=m" (p->thread.es));
-       asm("mov %%ds,%0" : "=m" (p->thread.ds));
+       savesegment(gs, p->thread.gsindex);
+       savesegment(fs, p->thread.fsindex);
+       savesegment(es, p->thread.es);
+       savesegment(ds, p->thread.ds);
 
        if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
@@ -408,7 +377,9 @@ out:
 void
 start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
 {
-       asm volatile("movl %0, %%fs; movl %0, %%es; movl %0, %%ds" :: "r"(0));
+       loadsegment(fs, 0);
+       loadsegment(es, 0);
+       loadsegment(ds, 0);
        load_gs_index(0);
        regs->ip                = new_ip;
        regs->sp                = new_sp;
@@ -567,6 +538,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                                 *next = &next_p->thread;
        int cpu = smp_processor_id();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
+       unsigned fsindex, gsindex;
 
        /* we're going to use this soon, after a few expensive things */
        if (next_p->fpu_counter>5)
@@ -581,22 +553,38 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         * Switch DS and ES.
         * This won't pick up thread selector changes, but I guess that is ok.
         */
-       asm volatile("mov %%es,%0" : "=m" (prev->es));
+       savesegment(es, prev->es);
        if (unlikely(next->es | prev->es))
                loadsegment(es, next->es); 
-       
-       asm volatile ("mov %%ds,%0" : "=m" (prev->ds));
+
+       savesegment(ds, prev->ds);
        if (unlikely(next->ds | prev->ds))
                loadsegment(ds, next->ds);
 
+
+       /* We must save %fs and %gs before load_TLS() because
+        * %fs and %gs may be cleared by load_TLS().
+        *
+        * (e.g. xen_load_tls())
+        */
+       savesegment(fs, fsindex);
+       savesegment(gs, gsindex);
+
        load_TLS(next, cpu);
 
+       /*
+        * Leave lazy mode, flushing any hypercalls made here.
+        * This must be done before restoring TLS segments so
+        * the GDT and LDT are properly updated, and must be
+        * done before math_state_restore, so the TS bit is up
+        * to date.
+        */
+       arch_leave_lazy_cpu_mode();
+
        /* 
         * Switch FS and GS.
         */
        { 
-               unsigned fsindex;
-               asm volatile("movl %%fs,%0" : "=r" (fsindex)); 
                /* segment register != 0 always requires a reload. 
                   also reload when it has changed. 
                   when prev process used 64bit base always reload
@@ -614,10 +602,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                if (next->fs) 
                        wrmsrl(MSR_FS_BASE, next->fs); 
                prev->fsindex = fsindex;
-       }
-       { 
-               unsigned gsindex;
-               asm volatile("movl %%gs,%0" : "=r" (gsindex)); 
+
                if (unlikely(gsindex | next->gsindex | prev->gs)) {
                        load_gs_index(next->gsindex);
                        if (gsindex)
@@ -798,7 +783,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
                        set_32bit_tls(task, FS_TLS, addr);
                        if (doit) {
                                load_TLS(&task->thread, cpu);
-                               asm volatile("movl %0,%%fs" :: "r"(FS_TLS_SEL));
+                               loadsegment(fs, FS_TLS_SEL);
                        }
                        task->thread.fsindex = FS_TLS_SEL;
                        task->thread.fs = 0;
@@ -808,7 +793,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
                        if (doit) {
                                /* set the selector to 0 to not confuse
                                   __switch_to */
-                               asm volatile("movl %0,%%fs" :: "r" (0));
+                               loadsegment(fs, 0);
                                ret = checking_wrmsrl(MSR_FS_BASE, addr);
                        }
                }
@@ -831,7 +816,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
                if (task->thread.gsindex == GS_TLS_SEL)
                        base = read_32bit_tls(task, GS_TLS);
                else if (doit) {
-                       asm("movl %%gs,%0" : "=r" (gsindex));
+                       savesegment(gs, gsindex);
                        if (gsindex)
                                rdmsrl(MSR_KERNEL_GS_BASE, base);
                        else
index a7835f2829361bcd964f85118839751fba24b12b..77040b6070e18c00ce71f788efa0d40d5a156229 100644 (file)
@@ -943,13 +943,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                return copy_regset_to_user(child, &user_x86_32_view,
                                           REGSET_XFP,
                                           0, sizeof(struct user_fxsr_struct),
-                                          datap);
+                                          datap) ? -EIO : 0;
 
        case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
                return copy_regset_from_user(child, &user_x86_32_view,
                                             REGSET_XFP,
                                             0, sizeof(struct user_fxsr_struct),
-                                            datap);
+                                            datap) ? -EIO : 0;
 #endif
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
index d89a648fe7109a5121673e08a6c978e5ef62a65d..79bdcd11c66e1b7c72220af7ee9ae388d1bebd20 100644 (file)
@@ -65,6 +65,7 @@ static enum {
        ICH_FORCE_HPET_RESUME,
        VT8237_FORCE_HPET_RESUME,
        NVIDIA_FORCE_HPET_RESUME,
+       ATI_FORCE_HPET_RESUME,
 } force_hpet_resume_type;
 
 static void __iomem *rcba_base;
@@ -158,6 +159,8 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0,
+                        ich_force_enable_hpet);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
                         ich_force_enable_hpet);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,
@@ -174,6 +177,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7,
 
 static struct pci_dev *cached_dev;
 
+static void hpet_print_force_info(void)
+{
+       printk(KERN_INFO "HPET not enabled in BIOS. "
+              "You might try hpet=force boot option\n");
+}
+
 static void old_ich_force_hpet_resume(void)
 {
        u32 val;
@@ -253,6 +262,8 @@ static void old_ich_force_enable_hpet_user(struct pci_dev *dev)
 {
        if (hpet_force_user)
                old_ich_force_enable_hpet(dev);
+       else
+               hpet_print_force_info();
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
@@ -290,8 +301,13 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev)
 {
        u32 uninitialized_var(val);
 
-       if (!hpet_force_user || hpet_address || force_hpet_address)
+       if (hpet_address || force_hpet_address)
+               return;
+
+       if (!hpet_force_user) {
+               hpet_print_force_info();
                return;
+       }
 
        pci_read_config_dword(dev, 0x68, &val);
        /*
@@ -330,6 +346,36 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
                         vt8237_force_enable_hpet);
 
+static void ati_force_hpet_resume(void)
+{
+       pci_write_config_dword(cached_dev, 0x14, 0xfed00000);
+       printk(KERN_DEBUG "Force enabled HPET at resume\n");
+}
+
+static void ati_force_enable_hpet(struct pci_dev *dev)
+{
+       u32 uninitialized_var(val);
+
+       if (hpet_address || force_hpet_address)
+               return;
+
+       if (!hpet_force_user) {
+               hpet_print_force_info();
+               return;
+       }
+
+       pci_write_config_dword(dev, 0x14, 0xfed00000);
+       pci_read_config_dword(dev, 0x14, &val);
+       force_hpet_address = val;
+       force_hpet_resume_type = ATI_FORCE_HPET_RESUME;
+       dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
+                  force_hpet_address);
+       cached_dev = dev;
+       return;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+                        ati_force_enable_hpet);
+
 /*
  * Undocumented chipset feature taken from LinuxBIOS.
  */
@@ -343,8 +389,13 @@ static void nvidia_force_enable_hpet(struct pci_dev *dev)
 {
        u32 uninitialized_var(val);
 
-       if (!hpet_force_user || hpet_address || force_hpet_address)
+       if (hpet_address || force_hpet_address)
+               return;
+
+       if (!hpet_force_user) {
+               hpet_print_force_info();
                return;
+       }
 
        pci_write_config_dword(dev, 0x44, 0xfed00001);
        pci_read_config_dword(dev, 0x44, &val);
@@ -397,6 +448,9 @@ void force_hpet_resume(void)
        case NVIDIA_FORCE_HPET_RESUME:
                nvidia_force_hpet_resume();
                return;
+       case ATI_FORCE_HPET_RESUME:
+               ati_force_hpet_resume();
+               return;
        default:
                break;
        }
index f6be7d5f82f81d726bf3545732c1d78ad778b0f3..f8a62160e1513221a379a400cfd30dc6e3eaaf0b 100644 (file)
@@ -27,7 +27,7 @@
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
-static long no_idt[3];
+static const struct desc_ptr no_idt = {};
 static int reboot_mode;
 enum reboot_type reboot_type = BOOT_KBD;
 int reboot_force;
@@ -201,15 +201,15 @@ core_initcall(reboot_init);
    controller to pulse the CPU reset line, which is more thorough, but
    doesn't work with at least one type of 486 motherboard.  It is easy
    to stop this code working; hence the copious comments. */
-static unsigned long long
+static const unsigned long long
 real_mode_gdt_entries [3] =
 {
        0x0000000000000000ULL,  /* Null descriptor */
-       0x00009a000000ffffULL,  /* 16-bit real-mode 64k code at 0x00000000 */
-       0x000092000100ffffULL   /* 16-bit real-mode 64k data at 0x00000100 */
+       0x00009b000000ffffULL,  /* 16-bit real-mode 64k code at 0x00000000 */
+       0x000093000100ffffULL   /* 16-bit real-mode 64k data at 0x00000100 */
 };
 
-static struct desc_ptr
+static const struct desc_ptr
 real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
 real_mode_idt = { 0x3ff, 0 };
 
@@ -231,7 +231,7 @@ real_mode_idt = { 0x3ff, 0 };
 
    More could be done here to set up the registers as if a CPU reset had
    occurred; hopefully real BIOSs don't assume much. */
-static unsigned char real_mode_switch [] =
+static const unsigned char real_mode_switch [] =
 {
        0x66, 0x0f, 0x20, 0xc0,                 /*    movl  %cr0,%eax        */
        0x66, 0x83, 0xe0, 0x11,                 /*    andl  $0x00000011,%eax */
@@ -245,7 +245,7 @@ static unsigned char real_mode_switch [] =
        0x24, 0x10,                             /* f: andb  $0x10,al         */
        0x66, 0x0f, 0x22, 0xc0                  /*    movl  %eax,%cr0        */
 };
-static unsigned char jump_to_bios [] =
+static const unsigned char jump_to_bios [] =
 {
        0xea, 0x00, 0x00, 0xff, 0xff            /*    ljmp  $0xffff,$0x0000  */
 };
@@ -255,7 +255,7 @@ static unsigned char jump_to_bios [] =
  * specified by the code and length parameters.
  * We assume that length will aways be less that 100!
  */
-void machine_real_restart(unsigned char *code, int length)
+void machine_real_restart(const unsigned char *code, int length)
 {
        local_irq_disable();
 
@@ -368,7 +368,7 @@ static void native_machine_emergency_restart(void)
                        }
 
                case BOOT_TRIPLE:
-                       load_idt((const struct desc_ptr *)&no_idt);
+                       load_idt(&no_idt);
                        __asm__ __volatile__("int3");
 
                        reboot_type = BOOT_KBD;
index dec0b5ec25c2fb18000af506d5493a623c40ad8a..61a837743fe5b7f91284bdfc97826ee802917132 100644 (file)
@@ -49,7 +49,7 @@ struct device_fixup {
        void (*reboot_fixup)(struct pci_dev *);
 };
 
-static struct device_fixup fixups_table[] = {
+static const struct device_fixup fixups_table[] = {
 { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, cs5530a_warm_reset },
 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, cs5536_warm_reset },
 { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE, cs5530a_warm_reset },
@@ -64,7 +64,7 @@ static struct device_fixup fixups_table[] = {
  */
 void mach_reboot_fixups(void)
 {
-       struct device_fixup *cur;
+       const struct device_fixup *cur;
        struct pci_dev *dev;
        int i;
 
index 6f80b852a1961a6b496bc2404c5194769557d97a..36c540d4ac4b6164dbd02d6b23951ea1315f134f 100644 (file)
-#include <linux/kernel.h>
+/*
+ *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ *
+ *  Memory region support
+ *     David Parsons <orc@pell.chi.il.us>, July-August 1999
+ *
+ *  Added E820 sanitization routine (removes overlapping memory regions);
+ *  Brian Moyle <bmoyle@mvista.com>, February 2001
+ *
+ * Moved CPU detection code to cpu/${cpu}.c
+ *    Patrick Mochel <mochel@osdl.org>, March 2002
+ *
+ *  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *  Alex Achenbach <xela@slit.de>, December 2002.
+ *
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/screen_info.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/apm_bios.h>
+#include <linux/initrd.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/mca.h>
+#include <linux/root_dev.h>
+#include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/efi.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/edd.h>
+#include <linux/iscsi_ibft.h>
+#include <linux/nodemask.h>
+#include <linux/kexec.h>
+#include <linux/dmi.h>
+#include <linux/pfn.h>
+#include <linux/pci.h>
+#include <asm/pci-direct.h>
+#include <linux/init_ohci1394_dma.h>
+#include <linux/kvm_para.h>
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/delay.h>
+#include <linux/highmem.h>
+
+#include <linux/kallsyms.h>
+#include <linux/edd.h>
+#include <linux/iscsi_ibft.h>
+#include <linux/kexec.h>
+#include <linux/cpufreq.h>
+#include <linux/dma-mapping.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+
 #include <linux/percpu.h>
+#include <linux/crash_dump.h>
+
+#include <video/edid.h>
+
+#include <asm/mtrr.h>
+#include <asm/apic.h>
+#include <asm/e820.h>
+#include <asm/mpspec.h>
+#include <asm/setup.h>
+#include <asm/arch_hooks.h>
+#include <asm/efi.h>
+#include <asm/sections.h>
+#include <asm/dmi.h>
+#include <asm/io_apic.h>
+#include <asm/ist.h>
+#include <asm/vmi.h>
+#include <setup_arch.h>
+#include <asm/bios_ebda.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+#include <asm/bugs.h>
+
+#include <asm/system.h>
+#include <asm/vsyscall.h>
 #include <asm/smp.h>
+#include <asm/desc.h>
+#include <asm/dma.h>
+#include <asm/gart.h>
+#include <asm/mmu_context.h>
+#include <asm/proto.h>
+
+#include <mach_apic.h>
+#include <asm/paravirt.h>
+
 #include <asm/percpu.h>
 #include <asm/sections.h>
-#include <asm/processor.h>
-#include <asm/setup.h>
 #include <asm/topology.h>
-#include <asm/mpspec.h>
 #include <asm/apicdef.h>
+#ifdef CONFIG_X86_64
+#include <asm/numa_64.h>
+#endif
 
-#ifdef CONFIG_X86_LOCAL_APIC
-unsigned int num_processors;
-unsigned disabled_cpus __cpuinitdata;
-/* Processor that is doing the boot up */
-unsigned int boot_cpu_physical_apicid = -1U;
-EXPORT_SYMBOL(boot_cpu_physical_apicid);
+#ifndef ARCH_SETUP
+#define ARCH_SETUP
+#endif
+
+#ifndef CONFIG_DEBUG_BOOT_PARAMS
+struct boot_params __initdata boot_params;
+#else
+struct boot_params boot_params;
+#endif
+
+/*
+ * Machine setup..
+ */
+static struct resource data_resource = {
+       .name   = "Kernel data",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource code_resource = {
+       .name   = "Kernel code",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource bss_resource = {
+       .name   = "Kernel bss",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+
+#ifdef CONFIG_X86_32
+/* This value is set up by the early boot code to point to the value
+   immediately after the boot time page tables.  It contains a *physical*
+   address, and must not be in the .bss segment! */
+unsigned long init_pg_tables_start __initdata = ~0UL;
+unsigned long init_pg_tables_end __initdata = ~0UL;
+
+static struct resource video_ram_resource = {
+       .name   = "Video RAM area",
+       .start  = 0xa0000,
+       .end    = 0xbffff,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+/* cpu data as detected by the assembly code in head.S */
+struct cpuinfo_x86 new_cpu_data __cpuinitdata = {0, 0, 0, 0, -1, 1, 0, 0, -1};
+/* common cpu data for all cpus */
+struct cpuinfo_x86 boot_cpu_data __read_mostly = {0, 0, 0, 0, -1, 1, 0, 0, -1};
+EXPORT_SYMBOL(boot_cpu_data);
+static void set_mca_bus(int x)
+{
+#ifdef CONFIG_MCA
+       MCA_bus = x;
+#endif
+}
+
+unsigned int def_to_bigsmp;
+
+/* for MCA, but anyone else can use it if they want */
+unsigned int machine_id;
+unsigned int machine_submodel_id;
+unsigned int BIOS_revision;
+
+struct apm_info apm_info;
+EXPORT_SYMBOL(apm_info);
+
+#if defined(CONFIG_X86_SPEEDSTEP_SMI) || \
+       defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
+struct ist_info ist_info;
+EXPORT_SYMBOL(ist_info);
+#else
+struct ist_info ist_info;
+#endif
+
+#else
+struct cpuinfo_x86 boot_cpu_data __read_mostly;
+EXPORT_SYMBOL(boot_cpu_data);
+#endif
 
-DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID;
-EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid);
 
-/* Bitmask of physically existing CPUs */
-physid_mask_t phys_cpu_present_map;
+#if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64)
+unsigned long mmu_cr4_features;
+#else
+unsigned long mmu_cr4_features = X86_CR4_PAE;
 #endif
 
-#if defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) && defined(CONFIG_X86_SMP)
+/* Boot loader ID as an integer, for the benefit of proc_dointvec */
+int bootloader_type;
+
 /*
- * Copy data used in early init routines from the initial arrays to the
- * per cpu data areas.  These arrays then become expendable and the
- * *_early_ptr's are zeroed indicating that the static arrays are gone.
+ * Early DMI memory
  */
-static void __init setup_per_cpu_maps(void)
+int dmi_alloc_index;
+char dmi_alloc_data[DMI_MAX_DATA];
+
+/*
+ * Setup options
+ */
+struct screen_info screen_info;
+EXPORT_SYMBOL(screen_info);
+struct edid_info edid_info;
+EXPORT_SYMBOL_GPL(edid_info);
+
+extern int root_mountflags;
+
+unsigned long saved_video_mode;
+
+#define RAMDISK_IMAGE_START_MASK       0x07FF
+#define RAMDISK_PROMPT_FLAG            0x8000
+#define RAMDISK_LOAD_FLAG              0x4000
+
+static char __initdata command_line[COMMAND_LINE_SIZE];
+
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+struct edd edd;
+#ifdef CONFIG_EDD_MODULE
+EXPORT_SYMBOL(edd);
+#endif
+/**
+ * copy_edd() - Copy the BIOS EDD information
+ *              from boot_params into a safe place.
+ *
+ */
+static inline void copy_edd(void)
+{
+     memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer,
+           sizeof(edd.mbr_signature));
+     memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info));
+     edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries;
+     edd.edd_info_nr = boot_params.eddbuf_entries;
+}
+#else
+static inline void copy_edd(void)
+{
+}
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+#ifdef CONFIG_X86_32
+
+#define MAX_MAP_CHUNK  (NR_FIX_BTMAPS << PAGE_SHIFT)
+static void __init relocate_initrd(void)
 {
-       int cpu;
 
-       for_each_possible_cpu(cpu) {
-               per_cpu(x86_cpu_to_apicid, cpu) = x86_cpu_to_apicid_init[cpu];
-               per_cpu(x86_bios_cpu_apicid, cpu) =
-                                               x86_bios_cpu_apicid_init[cpu];
-#ifdef CONFIG_NUMA
-               per_cpu(x86_cpu_to_node_map, cpu) =
-                                               x86_cpu_to_node_map_init[cpu];
+       u64 ramdisk_image = boot_params.hdr.ramdisk_image;
+       u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
+       u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT;
+       u64 ramdisk_here;
+       unsigned long slop, clen, mapaddr;
+       char *p, *q;
+
+       /* We need to move the initrd down into lowmem */
+       ramdisk_here = find_e820_area(0, end_of_lowmem, ramdisk_size,
+                                        PAGE_SIZE);
+
+       if (ramdisk_here == -1ULL)
+               panic("Cannot find place for new RAMDISK of size %lld\n",
+                        ramdisk_size);
+
+       /* Note: this includes all the lowmem currently occupied by
+          the initrd, we rely on that fact to keep the data intact. */
+       reserve_early(ramdisk_here, ramdisk_here + ramdisk_size,
+                        "NEW RAMDISK");
+       initrd_start = ramdisk_here + PAGE_OFFSET;
+       initrd_end   = initrd_start + ramdisk_size;
+       printk(KERN_INFO "Allocated new RAMDISK: %08llx - %08llx\n",
+                        ramdisk_here, ramdisk_here + ramdisk_size);
+
+       q = (char *)initrd_start;
+
+       /* Copy any lowmem portion of the initrd */
+       if (ramdisk_image < end_of_lowmem) {
+               clen = end_of_lowmem - ramdisk_image;
+               p = (char *)__va(ramdisk_image);
+               memcpy(q, p, clen);
+               q += clen;
+               ramdisk_image += clen;
+               ramdisk_size  -= clen;
+       }
+
+       /* Copy the highmem portion of the initrd */
+       while (ramdisk_size) {
+               slop = ramdisk_image & ~PAGE_MASK;
+               clen = ramdisk_size;
+               if (clen > MAX_MAP_CHUNK-slop)
+                       clen = MAX_MAP_CHUNK-slop;
+               mapaddr = ramdisk_image & PAGE_MASK;
+               p = early_ioremap(mapaddr, clen+slop);
+               memcpy(q, p+slop, clen);
+               early_iounmap(p, clen+slop);
+               q += clen;
+               ramdisk_image += clen;
+               ramdisk_size  -= clen;
+       }
+       /* high pages is not converted by early_res_to_bootmem */
+       ramdisk_image = boot_params.hdr.ramdisk_image;
+       ramdisk_size  = boot_params.hdr.ramdisk_size;
+       printk(KERN_INFO "Move RAMDISK from %016llx - %016llx to"
+               " %08llx - %08llx\n",
+               ramdisk_image, ramdisk_image + ramdisk_size - 1,
+               ramdisk_here, ramdisk_here + ramdisk_size - 1);
+}
 #endif
+
+static void __init reserve_initrd(void)
+{
+       u64 ramdisk_image = boot_params.hdr.ramdisk_image;
+       u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
+       u64 ramdisk_end   = ramdisk_image + ramdisk_size;
+       u64 end_of_lowmem = max_low_pfn << PAGE_SHIFT;
+
+       if (!boot_params.hdr.type_of_loader ||
+           !ramdisk_image || !ramdisk_size)
+               return;         /* No initrd provided by bootloader */
+
+       initrd_start = 0;
+
+       if (ramdisk_size >= (end_of_lowmem>>1)) {
+               free_early(ramdisk_image, ramdisk_end);
+               printk(KERN_ERR "initrd too large to handle, "
+                      "disabling initrd\n");
+               return;
+       }
+
+       printk(KERN_INFO "RAMDISK: %08llx - %08llx\n", ramdisk_image,
+                       ramdisk_end);
+
+
+       if (ramdisk_end <= end_of_lowmem) {
+               /* All in lowmem, easy case */
+               /*
+                * don't need to reserve again, already reserved early
+                * in i386_start_kernel
+                */
+               initrd_start = ramdisk_image + PAGE_OFFSET;
+               initrd_end = initrd_start + ramdisk_size;
+               return;
        }
 
-       /* indicate the early static arrays will soon be gone */
-       x86_cpu_to_apicid_early_ptr = NULL;
-       x86_bios_cpu_apicid_early_ptr = NULL;
-#ifdef CONFIG_NUMA
-       x86_cpu_to_node_map_early_ptr = NULL;
+#ifdef CONFIG_X86_32
+       relocate_initrd();
+#else
+       printk(KERN_ERR "initrd extends beyond end of memory "
+              "(0x%08llx > 0x%08llx)\ndisabling initrd\n",
+              ramdisk_end, end_of_lowmem);
+       initrd_start = 0;
 #endif
+       free_early(ramdisk_image, ramdisk_end);
 }
+#else
+static void __init reserve_initrd(void)
+{
+}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+static void __init parse_setup_data(void)
+{
+       struct setup_data *data;
+       u64 pa_data;
+
+       if (boot_params.hdr.version < 0x0209)
+               return;
+       pa_data = boot_params.hdr.setup_data;
+       while (pa_data) {
+               data = early_ioremap(pa_data, PAGE_SIZE);
+               switch (data->type) {
+               case SETUP_E820_EXT:
+                       parse_e820_ext(data, pa_data);
+                       break;
+               default:
+                       break;
+               }
+               pa_data = data->next;
+               early_iounmap(data, PAGE_SIZE);
+       }
+}
+
+static void __init e820_reserve_setup_data(void)
+{
+       struct setup_data *data;
+       u64 pa_data;
+       int found = 0;
+
+       if (boot_params.hdr.version < 0x0209)
+               return;
+       pa_data = boot_params.hdr.setup_data;
+       while (pa_data) {
+               data = early_ioremap(pa_data, sizeof(*data));
+               e820_update_range(pa_data, sizeof(*data)+data->len,
+                        E820_RAM, E820_RESERVED_KERN);
+               found = 1;
+               pa_data = data->next;
+               early_iounmap(data, sizeof(*data));
+       }
+       if (!found)
+               return;
 
-#ifdef CONFIG_HAVE_CPUMASK_OF_CPU_MAP
-cpumask_t *cpumask_of_cpu_map __read_mostly;
-EXPORT_SYMBOL(cpumask_of_cpu_map);
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+       memcpy(&e820_saved, &e820, sizeof(struct e820map));
+       printk(KERN_INFO "extended physical RAM map:\n");
+       e820_print_map("reserve setup_data");
+}
 
-/* requires nr_cpu_ids to be initialized */
-static void __init setup_cpumask_of_cpu(void)
+static void __init reserve_early_setup_data(void)
 {
-       int i;
+       struct setup_data *data;
+       u64 pa_data;
+       char buf[32];
+
+       if (boot_params.hdr.version < 0x0209)
+               return;
+       pa_data = boot_params.hdr.setup_data;
+       while (pa_data) {
+               data = early_ioremap(pa_data, sizeof(*data));
+               sprintf(buf, "setup data %x", data->type);
+               reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
+               pa_data = data->next;
+               early_iounmap(data, sizeof(*data));
+       }
+}
+
+/*
+ * --------- Crashkernel reservation ------------------------------
+ */
+
+#ifdef CONFIG_KEXEC
+
+/**
+ * Reserve @size bytes of crashkernel memory at any suitable offset.
+ *
+ * @size: Size of the crashkernel memory to reserve.
+ * Returns the base address on success, and -1ULL on failure.
+ */
+unsigned long long find_and_reserve_crashkernel(unsigned long long size)
+{
+       const unsigned long long alignment = 16<<20;    /* 16M */
+       unsigned long long start = 0LL;
+
+       while (1) {
+               int ret;
+
+               start = find_e820_area(start, ULONG_MAX, size, alignment);
+               if (start == -1ULL)
+                       return start;
+
+               /* try to reserve it */
+               ret = reserve_bootmem_generic(start, size, BOOTMEM_EXCLUSIVE);
+               if (ret >= 0)
+                       return start;
+
+               start += alignment;
+       }
+}
 
-       /* alloc_bootmem zeroes memory */
-       cpumask_of_cpu_map = alloc_bootmem_low(sizeof(cpumask_t) * nr_cpu_ids);
-       for (i = 0; i < nr_cpu_ids; i++)
-               cpu_set(i, cpumask_of_cpu_map[i]);
+static inline unsigned long long get_total_mem(void)
+{
+       unsigned long long total;
+
+       total = max_low_pfn - min_low_pfn;
+#ifdef CONFIG_HIGHMEM
+       total += highend_pfn - highstart_pfn;
+#endif
+
+       return total << PAGE_SHIFT;
+}
+
+static void __init reserve_crashkernel(void)
+{
+       unsigned long long total_mem;
+       unsigned long long crash_size, crash_base;
+       int ret;
+
+       total_mem = get_total_mem();
+
+       ret = parse_crashkernel(boot_command_line, total_mem,
+                       &crash_size, &crash_base);
+       if (ret != 0 || crash_size <= 0)
+               return;
+
+       /* 0 means: find the address automatically */
+       if (crash_base <= 0) {
+               crash_base = find_and_reserve_crashkernel(crash_size);
+               if (crash_base == -1ULL) {
+                       pr_info("crashkernel reservation failed. "
+                               "No suitable area found.\n");
+                       return;
+               }
+       } else {
+               ret = reserve_bootmem_generic(crash_base, crash_size,
+                                       BOOTMEM_EXCLUSIVE);
+               if (ret < 0) {
+                       pr_info("crashkernel reservation failed - "
+                               "memory is in use\n");
+                       return;
+               }
+       }
+
+       printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
+                       "for crashkernel (System RAM: %ldMB)\n",
+                       (unsigned long)(crash_size >> 20),
+                       (unsigned long)(crash_base >> 20),
+                       (unsigned long)(total_mem >> 20));
+
+       crashk_res.start = crash_base;
+       crashk_res.end   = crash_base + crash_size - 1;
+       insert_resource(&iomem_resource, &crashk_res);
 }
 #else
-static inline void setup_cpumask_of_cpu(void) { }
+static void __init reserve_crashkernel(void)
+{
+}
 #endif
 
-#ifdef CONFIG_X86_32
-/*
- * Great future not-so-futuristic plan: make i386 and x86_64 do it
- * the same way
+static struct resource standard_io_resources[] = {
+       { .name = "dma1", .start = 0x00, .end = 0x1f,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "pic1", .start = 0x20, .end = 0x21,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "timer0", .start = 0x40, .end = 0x43,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "timer1", .start = 0x50, .end = 0x53,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "keyboard", .start = 0x60, .end = 0x60,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "keyboard", .start = 0x64, .end = 0x64,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "dma page reg", .start = 0x80, .end = 0x8f,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "pic2", .start = 0xa0, .end = 0xa1,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "dma2", .start = 0xc0, .end = 0xdf,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
+       { .name = "fpu", .start = 0xf0, .end = 0xff,
+               .flags = IORESOURCE_BUSY | IORESOURCE_IO }
+};
+
+static void __init reserve_standard_io_resources(void)
+{
+       int i;
+
+       /* request I/O space for devices used on all i[345]86 PCs */
+       for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
+               request_resource(&ioport_resource, &standard_io_resources[i]);
+
+}
+
+#ifdef CONFIG_PROC_VMCORE
+/* elfcorehdr= specifies the location of elf core header
+ * stored by the crashed kernel. This option will be passed
+ * by kexec loader to the capture kernel.
  */
-unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
-EXPORT_SYMBOL(__per_cpu_offset);
+static int __init setup_elfcorehdr(char *arg)
+{
+       char *end;
+       if (!arg)
+               return -EINVAL;
+       elfcorehdr_addr = memparse(arg, &end);
+       return end > arg ? 0 : -EINVAL;
+}
+early_param("elfcorehdr", setup_elfcorehdr);
 #endif
 
 /*
- * Great future plan:
- * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
- * Always point %gs to its beginning
+ * Determine if we were loaded by an EFI loader.  If so, then we have also been
+ * passed the efi memmap, systab, etc., so we should use these data structures
+ * for initialization.  Note, the efi init code path is determined by the
+ * global efi_enabled. This allows the same kernel image to be used on existing
+ * systems (with a traditional BIOS) as well as on EFI systems.
  */
-void __init setup_per_cpu_areas(void)
+/*
+ * setup_arch - architecture-specific boot-time initializations
+ *
+ * Note: On x86_64, fixmaps are ready for use even before this is called.
+ */
+
+void __init setup_arch(char **cmdline_p)
 {
-       int i, highest_cpu = 0;
-       unsigned long size;
+#ifdef CONFIG_X86_32
+       memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
+       visws_early_detect();
+       pre_setup_arch_hook();
+       early_cpu_init();
+#else
+       printk(KERN_INFO "Command line: %s\n", boot_command_line);
+#endif
 
-#ifdef CONFIG_HOTPLUG_CPU
-       prefill_possible_map();
+       early_ioremap_init();
+
+       ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
+       screen_info = boot_params.screen_info;
+       edid_info = boot_params.edid_info;
+#ifdef CONFIG_X86_32
+       apm_info.bios = boot_params.apm_bios_info;
+       ist_info = boot_params.ist_info;
+       if (boot_params.sys_desc_table.length != 0) {
+               set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
+               machine_id = boot_params.sys_desc_table.table[0];
+               machine_submodel_id = boot_params.sys_desc_table.table[1];
+               BIOS_revision = boot_params.sys_desc_table.table[2];
+       }
+#endif
+       saved_video_mode = boot_params.hdr.vid_mode;
+       bootloader_type = boot_params.hdr.type_of_loader;
+
+#ifdef CONFIG_BLK_DEV_RAM
+       rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
+       rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
+       rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
 #endif
+#ifdef CONFIG_EFI
+       if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
+#ifdef CONFIG_X86_32
+                    "EL32",
+#else
+                    "EL64",
+#endif
+        4)) {
+               efi_enabled = 1;
+               efi_reserve_early();
+       }
+#endif
+
+       ARCH_SETUP
 
-       /* Copy section for each CPU (we discard the original) */
-       size = PERCPU_ENOUGH_ROOM;
-       printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n",
-                         size);
+       setup_memory_map();
+       parse_setup_data();
+       /* update the e820_saved too */
+       e820_reserve_setup_data();
 
-       for_each_possible_cpu(i) {
-               char *ptr;
-#ifndef CONFIG_NEED_MULTIPLE_NODES
-               ptr = alloc_bootmem_pages(size);
+       copy_edd();
+
+       if (!boot_params.hdr.root_flags)
+               root_mountflags &= ~MS_RDONLY;
+       init_mm.start_code = (unsigned long) _text;
+       init_mm.end_code = (unsigned long) _etext;
+       init_mm.end_data = (unsigned long) _edata;
+#ifdef CONFIG_X86_32
+       init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
 #else
-               int node = early_cpu_to_node(i);
-               if (!node_online(node) || !NODE_DATA(node)) {
-                       ptr = alloc_bootmem_pages(size);
-                       printk(KERN_INFO
-                              "cpu %d has no node or node-local memory\n", i);
-               }
-               else
-                       ptr = alloc_bootmem_pages_node(NODE_DATA(node), size);
+       init_mm.brk = (unsigned long) &_end;
 #endif
-               if (!ptr)
-                       panic("Cannot allocate cpu data for CPU %d\n", i);
+
+       code_resource.start = virt_to_phys(_text);
+       code_resource.end = virt_to_phys(_etext)-1;
+       data_resource.start = virt_to_phys(_etext);
+       data_resource.end = virt_to_phys(_edata)-1;
+       bss_resource.start = virt_to_phys(&__bss_start);
+       bss_resource.end = virt_to_phys(&__bss_stop)-1;
+
 #ifdef CONFIG_X86_64
-               cpu_pda(i)->data_offset = ptr - __per_cpu_start;
+       early_cpu_init();
+#endif
+       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+       *cmdline_p = command_line;
+
+       parse_early_param();
+
+       /* after early param, so could get panic from serial */
+       reserve_early_setup_data();
+
+       if (acpi_mps_check()) {
+#ifdef CONFIG_X86_LOCAL_APIC
+               disable_apic = 1;
+#endif
+               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC);
+       }
+
+       finish_e820_parsing();
+
+#ifdef CONFIG_X86_32
+       probe_roms();
+#endif
+
+       /* after parse_early_param, so could debug it */
+       insert_resource(&iomem_resource, &code_resource);
+       insert_resource(&iomem_resource, &data_resource);
+       insert_resource(&iomem_resource, &bss_resource);
+
+       if (efi_enabled)
+               efi_init();
+
+#ifdef CONFIG_X86_32
+       if (ppro_with_ram_bug()) {
+               e820_update_range(0x70000000ULL, 0x40000ULL, E820_RAM,
+                                 E820_RESERVED);
+               sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+               printk(KERN_INFO "fixed physical RAM map:\n");
+               e820_print_map("bad_ppro");
+       }
+#else
+       early_gart_iommu_check();
+#endif
+
+       /*
+        * partially used pages are not usable - thus
+        * we are rounding upwards:
+        */
+       max_pfn = e820_end_of_ram_pfn();
+
+       /* preallocate 4k for mptable mpc */
+       early_reserve_e820_mpc_new();
+       /* update e820 for memory not covered by WB MTRRs */
+       mtrr_bp_init();
+       if (mtrr_trim_uncached_memory(max_pfn))
+               max_pfn = e820_end_of_ram_pfn();
+
+#ifdef CONFIG_X86_32
+       /* max_low_pfn get updated here */
+       find_low_pfn_range();
 #else
-               __per_cpu_offset[i] = ptr - __per_cpu_start;
+       num_physpages = max_pfn;
+
+       check_efer();
+
+       /* How many end-of-memory variables you have, grandma! */
+       /* need this before calling reserve_initrd */
+       if (max_pfn > (1UL<<(32 - PAGE_SHIFT)))
+               max_low_pfn = e820_end_of_low_ram_pfn();
+       else
+               max_low_pfn = max_pfn;
+
+       high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
 #endif
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
 
-               highest_cpu = i;
+       /* max_pfn_mapped is updated here */
+       max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
+       max_pfn_mapped = max_low_pfn_mapped;
+
+#ifdef CONFIG_X86_64
+       if (max_pfn > max_low_pfn) {
+               max_pfn_mapped = init_memory_mapping(1UL<<32,
+                                                    max_pfn<<PAGE_SHIFT);
+               /* can we preseve max_low_pfn ?*/
+               max_low_pfn = max_pfn;
        }
+#endif
+
+       /*
+        * NOTE: On x86-32, only from this point on, fixmaps are ready for use.
+        */
 
-       nr_cpu_ids = highest_cpu + 1;
-       printk(KERN_DEBUG "NR_CPUS: %d, nr_cpu_ids: %d\n", NR_CPUS, nr_cpu_ids);
+#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
+       if (init_ohci1394_dma_early)
+               init_ohci1394_dma_on_all_controllers();
+#endif
 
-       /* Setup percpu data maps */
-       setup_per_cpu_maps();
+       reserve_initrd();
 
-       /* Setup cpumask_of_cpu map */
-       setup_cpumask_of_cpu();
-}
+#ifdef CONFIG_X86_64
+       vsmp_init();
+#endif
+
+       dmi_scan_machine();
+
+       io_delay_init();
+
+       /*
+        * Parse the ACPI tables for possible boot-time SMP configuration.
+        */
+       acpi_boot_table_init();
+
+#ifdef CONFIG_ACPI_NUMA
+       /*
+        * Parse SRAT to discover nodes.
+        */
+       acpi_numa_init();
+#endif
+
+       initmem_init(0, max_pfn);
+
+#ifdef CONFIG_X86_64
+       dma32_reserve_bootmem();
+#endif
 
+#ifdef CONFIG_ACPI_SLEEP
+       /*
+        * Reserve low memory region for sleep support.
+        */
+       acpi_reserve_bootmem();
+#endif
+#ifdef CONFIG_X86_FIND_SMP_CONFIG
+       /*
+        * Find and reserve possible boot-time SMP configuration:
+        */
+       find_smp_config();
 #endif
+       reserve_crashkernel();
+
+       reserve_ibft_region();
+
+#ifdef CONFIG_KVM_CLOCK
+       kvmclock_init();
+#endif
+
+#if defined(CONFIG_VMI) && defined(CONFIG_X86_32)
+       /*
+        * Must be after max_low_pfn is determined, and before kernel
+        * pagetables are setup.
+        */
+       vmi_init();
+#endif
+
+       paging_init();
+
+#ifdef CONFIG_X86_64
+       map_vsyscall();
+#endif
+
+#ifdef CONFIG_X86_GENERICARCH
+       generic_apic_probe();
+#endif
+
+       early_quirks();
+
+       /*
+        * Read APIC and some other early information from ACPI tables.
+        */
+       acpi_boot_init();
+
+#if defined(CONFIG_X86_MPPARSE) || defined(CONFIG_X86_VISWS)
+       /*
+        * get boot-time SMP configuration:
+        */
+       if (smp_found_config)
+               get_smp_config();
+#endif
+
+       prefill_possible_map();
+#ifdef CONFIG_X86_64
+       init_cpu_to_node();
+#endif
+
+#ifdef CONFIG_X86_NUMAQ
+       /*
+        * need to check online nodes num, call it
+        * here before time_init/tsc_init
+        */
+       numaq_tsc_disable();
+#endif
+
+       init_apic_mappings();
+       ioapic_init_mappings();
+
+#if defined(CONFIG_SMP) && defined(CONFIG_X86_PC) && defined(CONFIG_X86_32)
+       if (def_to_bigsmp)
+               printk(KERN_WARNING "More than 8 CPUs detected and "
+                       "CONFIG_X86_PC cannot handle it.\nUse "
+                       "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n");
+#endif
+       kvm_guest_init();
+
+       e820_reserve_resources();
+       e820_mark_nosave_regions(max_low_pfn);
+
+#ifdef CONFIG_X86_32
+       request_resource(&iomem_resource, &video_ram_resource);
+#endif
+       reserve_standard_io_resources();
+
+       e820_setup_gap();
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+       if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
+               conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+#endif
+#endif
+}
diff --git a/arch/x86/kernel/setup64.c b/arch/x86/kernel/setup64.c
deleted file mode 100644 (file)
index aee0e82..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/* 
- * X86-64 specific CPU setup.
- * Copyright (C) 1995  Linus Torvalds
- * Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen.
- * See setup.c for older changelog.
- */ 
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/kgdb.h>
-#include <asm/pda.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/mmu_context.h>
-#include <asm/smp.h>
-#include <asm/i387.h>
-#include <asm/percpu.h>
-#include <asm/proto.h>
-#include <asm/sections.h>
-#include <asm/setup.h>
-#include <asm/genapic.h>
-
-#ifndef CONFIG_DEBUG_BOOT_PARAMS
-struct boot_params __initdata boot_params;
-#else
-struct boot_params boot_params;
-#endif
-
-cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
-
-struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly;
-EXPORT_SYMBOL(_cpu_pda);
-struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned;
-
-struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
-
-char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
-
-unsigned long __supported_pte_mask __read_mostly = ~0UL;
-EXPORT_SYMBOL_GPL(__supported_pte_mask);
-
-static int do_not_nx __cpuinitdata = 0;
-
-/* noexec=on|off
-Control non executable mappings for 64bit 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; 
-               do_not_nx = 0; 
-       } else if (!strncmp(str, "off", 3)) {
-               do_not_nx = 1;
-               __supported_pte_mask &= ~_PAGE_NX;
-        }
-       return 0;
-} 
-early_param("noexec", nonx_setup);
-
-int force_personality32 = 0; 
-
-/* noexec32=on|off
-Control non executable heap for 32bit processes.
-To control the stack too use noexec=off
-
-on     PROT_READ does not imply PROT_EXEC for 32bit processes (default)
-off    PROT_READ implies PROT_EXEC
-*/
-static int __init nonx32_setup(char *str)
-{
-       if (!strcmp(str, "on"))
-               force_personality32 &= ~READ_IMPLIES_EXEC;
-       else if (!strcmp(str, "off"))
-               force_personality32 |= READ_IMPLIES_EXEC;
-       return 1;
-}
-__setup("noexec32=", nonx32_setup);
-
-void pda_init(int cpu)
-{ 
-       struct x8664_pda *pda = cpu_pda(cpu);
-
-       /* Setup up data that may be needed in __get_free_pages early */
-       asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); 
-       /* Memory clobbers used to order PDA accessed */
-       mb();
-       wrmsrl(MSR_GS_BASE, pda);
-       mb();
-
-       pda->cpunumber = cpu; 
-       pda->irqcount = -1;
-       pda->kernelstack = 
-               (unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE; 
-       pda->active_mm = &init_mm;
-       pda->mmu_state = 0;
-
-       if (cpu == 0) {
-               /* others are initialized in smpboot.c */
-               pda->pcurrent = &init_task;
-               pda->irqstackptr = boot_cpu_stack; 
-       } else {
-               pda->irqstackptr = (char *)
-                       __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
-               if (!pda->irqstackptr)
-                       panic("cannot allocate irqstack for cpu %d", cpu); 
-       }
-
-
-       pda->irqstackptr += IRQSTACKSIZE-64;
-} 
-
-char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]
-__attribute__((section(".bss.page_aligned")));
-
-extern asmlinkage void ignore_sysret(void);
-
-/* May not be marked __init: used by software suspend */
-void syscall_init(void)
-{
-       /* 
-        * LSTAR and STAR live in a bit strange symbiosis.
-        * They both write to the same internal register. STAR allows to set CS/DS
-        * but only a 32bit target. LSTAR sets the 64bit rip.    
-        */ 
-       wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32); 
-       wrmsrl(MSR_LSTAR, system_call); 
-       wrmsrl(MSR_CSTAR, ignore_sysret);
-
-#ifdef CONFIG_IA32_EMULATION                   
-       syscall32_cpu_init ();
-#endif
-
-       /* Flags to clear on syscall */
-       wrmsrl(MSR_SYSCALL_MASK,
-              X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL);
-}
-
-void __cpuinit check_efer(void)
-{
-       unsigned long efer;
-
-       rdmsrl(MSR_EFER, efer); 
-        if (!(efer & EFER_NX) || do_not_nx) { 
-                __supported_pte_mask &= ~_PAGE_NX; 
-        }       
-}
-
-unsigned long kernel_eflags;
-
-/*
- * Copies of the original ist values from the tss are only accessed during
- * debugging, no special alignment required.
- */
-DEFINE_PER_CPU(struct orig_ist, orig_ist);
-
-/*
- * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
- * A lot of state is already set up in PDA init.
- */
-void __cpuinit cpu_init (void)
-{
-       int cpu = stack_smp_processor_id();
-       struct tss_struct *t = &per_cpu(init_tss, cpu);
-       struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
-       unsigned long v; 
-       char *estacks = NULL; 
-       struct task_struct *me;
-       int i;
-
-       /* CPU 0 is initialised in head64.c */
-       if (cpu != 0) {
-               pda_init(cpu);
-       } else 
-               estacks = boot_exception_stacks; 
-
-       me = current;
-
-       if (cpu_test_and_set(cpu, cpu_initialized))
-               panic("CPU#%d already initialized!\n", cpu);
-
-       printk("Initializing CPU#%d\n", cpu);
-
-       clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
-
-       /*
-        * Initialize the per-CPU GDT with the boot GDT,
-        * and set up the GDT descriptor:
-        */
-       if (cpu)
-               memcpy(get_cpu_gdt_table(cpu), cpu_gdt_table, GDT_SIZE);
-
-       cpu_gdt_descr[cpu].size = GDT_SIZE;
-       load_gdt((const struct desc_ptr *)&cpu_gdt_descr[cpu]);
-       load_idt((const struct desc_ptr *)&idt_descr);
-
-       memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
-       syscall_init();
-
-       wrmsrl(MSR_FS_BASE, 0);
-       wrmsrl(MSR_KERNEL_GS_BASE, 0);
-       barrier(); 
-
-       check_efer();
-
-       /*
-        * set up and load the per-CPU TSS
-        */
-       for (v = 0; v < N_EXCEPTION_STACKS; v++) {
-               static const unsigned int order[N_EXCEPTION_STACKS] = {
-                       [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
-                       [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
-               };
-               if (cpu) {
-                       estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
-                       if (!estacks)
-                               panic("Cannot allocate exception stack %ld %d\n",
-                                     v, cpu); 
-               }
-               estacks += PAGE_SIZE << order[v];
-               orig_ist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks;
-       }
-
-       t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
-       /*
-        * <= is required because the CPU will access up to
-        * 8 bits beyond the end of the IO permission bitmap.
-        */
-       for (i = 0; i <= IO_BITMAP_LONGS; i++)
-               t->io_bitmap[i] = ~0UL;
-
-       atomic_inc(&init_mm.mm_count);
-       me->active_mm = &init_mm;
-       if (me->mm)
-               BUG();
-       enter_lazy_tlb(&init_mm, me);
-
-       set_tss_desc(cpu, t);
-       load_TR_desc();
-       load_LDT(&init_mm.context);
-
-#ifdef CONFIG_KGDB
-       /*
-        * If the kgdb is connected no debug regs should be altered.  This
-        * is only applicable when KGDB and a KGDB I/O module are built
-        * into the kernel and you are using early debugging with
-        * kgdbwait. KGDB will control the kernel HW breakpoint registers.
-        */
-       if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
-               arch_kgdb_ops.correct_hw_break();
-       else {
-#endif
-       /*
-        * Clear all 6 debug registers:
-        */
-
-       set_debugreg(0UL, 0);
-       set_debugreg(0UL, 1);
-       set_debugreg(0UL, 2);
-       set_debugreg(0UL, 3);
-       set_debugreg(0UL, 6);
-       set_debugreg(0UL, 7);
-#ifdef CONFIG_KGDB
-       /* If the kgdb is connected no debug regs should be altered. */
-       }
-#endif
-
-       fpu_init(); 
-
-       raw_local_save_flags(kernel_eflags);
-
-       if (is_uv_system())
-               uv_cpu_init();
-}
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
deleted file mode 100644 (file)
index 5a2f8e0..0000000
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
- *  Copyright (C) 1995  Linus Torvalds
- *
- *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
- *
- *  Memory region support
- *     David Parsons <orc@pell.chi.il.us>, July-August 1999
- *
- *  Added E820 sanitization routine (removes overlapping memory regions);
- *  Brian Moyle <bmoyle@mvista.com>, February 2001
- *
- * Moved CPU detection code to cpu/${cpu}.c
- *    Patrick Mochel <mochel@osdl.org>, March 2002
- *
- *  Provisions for empty E820 memory regions (reported by certain BIOSes).
- *  Alex Achenbach <xela@slit.de>, December 2002.
- *
- */
-
-/*
- * This file handles the architecture-dependent parts of initialization
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mmzone.h>
-#include <linux/screen_info.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/apm_bios.h>
-#include <linux/initrd.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/console.h>
-#include <linux/mca.h>
-#include <linux/root_dev.h>
-#include <linux/highmem.h>
-#include <linux/module.h>
-#include <linux/efi.h>
-#include <linux/init.h>
-#include <linux/edd.h>
-#include <linux/iscsi_ibft.h>
-#include <linux/nodemask.h>
-#include <linux/kexec.h>
-#include <linux/crash_dump.h>
-#include <linux/dmi.h>
-#include <linux/pfn.h>
-#include <linux/pci.h>
-#include <linux/init_ohci1394_dma.h>
-#include <linux/kvm_para.h>
-
-#include <video/edid.h>
-
-#include <asm/mtrr.h>
-#include <asm/apic.h>
-#include <asm/e820.h>
-#include <asm/mpspec.h>
-#include <asm/mmzone.h>
-#include <asm/setup.h>
-#include <asm/arch_hooks.h>
-#include <asm/sections.h>
-#include <asm/io_apic.h>
-#include <asm/ist.h>
-#include <asm/io.h>
-#include <asm/vmi.h>
-#include <setup_arch.h>
-#include <asm/bios_ebda.h>
-#include <asm/cacheflush.h>
-#include <asm/processor.h>
-
-/* This value is set up by the early boot code to point to the value
-   immediately after the boot time page tables.  It contains a *physical*
-   address, and must not be in the .bss segment! */
-unsigned long init_pg_tables_end __initdata = ~0UL;
-
-/*
- * Machine setup..
- */
-static struct resource data_resource = {
-       .name   = "Kernel data",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
-};
-
-static struct resource code_resource = {
-       .name   = "Kernel code",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
-};
-
-static struct resource bss_resource = {
-       .name   = "Kernel bss",
-       .start  = 0,
-       .end    = 0,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
-};
-
-static struct resource video_ram_resource = {
-       .name   = "Video RAM area",
-       .start  = 0xa0000,
-       .end    = 0xbffff,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
-};
-
-static struct resource standard_io_resources[] = { {
-       .name   = "dma1",
-       .start  = 0x0000,
-       .end    = 0x001f,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "pic1",
-       .start  = 0x0020,
-       .end    = 0x0021,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "timer0",
-       .start  = 0x0040,
-       .end    = 0x0043,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "timer1",
-       .start  = 0x0050,
-       .end    = 0x0053,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "keyboard",
-       .start  = 0x0060,
-       .end    = 0x0060,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "keyboard",
-       .start  = 0x0064,
-       .end    = 0x0064,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "dma page reg",
-       .start  = 0x0080,
-       .end    = 0x008f,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "pic2",
-       .start  = 0x00a0,
-       .end    = 0x00a1,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "dma2",
-       .start  = 0x00c0,
-       .end    = 0x00df,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-       .name   = "fpu",
-       .start  = 0x00f0,
-       .end    = 0x00ff,
-       .flags  = IORESOURCE_BUSY | IORESOURCE_IO
-} };
-
-/* cpu data as detected by the assembly code in head.S */
-struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
-/* common cpu data for all cpus */
-struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
-EXPORT_SYMBOL(boot_cpu_data);
-
-unsigned int def_to_bigsmp;
-
-#ifndef CONFIG_X86_PAE
-unsigned long mmu_cr4_features;
-#else
-unsigned long mmu_cr4_features = X86_CR4_PAE;
-#endif
-
-/* for MCA, but anyone else can use it if they want */
-unsigned int machine_id;
-unsigned int machine_submodel_id;
-unsigned int BIOS_revision;
-
-/* Boot loader ID as an integer, for the benefit of proc_dointvec */
-int bootloader_type;
-
-/* user-defined highmem size */
-static unsigned int highmem_pages = -1;
-
-/*
- * Setup options
- */
-struct screen_info screen_info;
-EXPORT_SYMBOL(screen_info);
-struct apm_info apm_info;
-EXPORT_SYMBOL(apm_info);
-struct edid_info edid_info;
-EXPORT_SYMBOL_GPL(edid_info);
-struct ist_info ist_info;
-#if defined(CONFIG_X86_SPEEDSTEP_SMI) || \
-       defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
-EXPORT_SYMBOL(ist_info);
-#endif
-
-extern void early_cpu_init(void);
-extern int root_mountflags;
-
-unsigned long saved_video_mode;
-
-#define RAMDISK_IMAGE_START_MASK       0x07FF
-#define RAMDISK_PROMPT_FLAG            0x8000
-#define RAMDISK_LOAD_FLAG              0x4000
-
-static char __initdata command_line[COMMAND_LINE_SIZE];
-
-#ifndef CONFIG_DEBUG_BOOT_PARAMS
-struct boot_params __initdata boot_params;
-#else
-struct boot_params boot_params;
-#endif
-
-#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-struct edd edd;
-#ifdef CONFIG_EDD_MODULE
-EXPORT_SYMBOL(edd);
-#endif
-/**
- * copy_edd() - Copy the BIOS EDD information
- *              from boot_params into a safe place.
- *
- */
-static inline void copy_edd(void)
-{
-     memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer,
-           sizeof(edd.mbr_signature));
-     memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info));
-     edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries;
-     edd.edd_info_nr = boot_params.eddbuf_entries;
-}
-#else
-static inline void copy_edd(void)
-{
-}
-#endif
-
-int __initdata user_defined_memmap;
-
-/*
- * "mem=nopentium" disables the 4MB page tables.
- * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
- * to <mem>, overriding the bios size.
- * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from
- * <start> to <start>+<mem>, overriding the bios size.
- *
- * HPA tells me bootloaders need to parse mem=, so no new
- * option should be mem=  [also see Documentation/i386/boot.txt]
- */
-static int __init parse_mem(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       if (strcmp(arg, "nopentium") == 0) {
-               setup_clear_cpu_cap(X86_FEATURE_PSE);
-       } else {
-               /* If the user specifies memory size, we
-                * limit the BIOS-provided memory map to
-                * that size. exactmap can be used to specify
-                * the exact map. mem=number can be used to
-                * trim the existing memory map.
-                */
-               unsigned long long mem_size;
-
-               mem_size = memparse(arg, &arg);
-               limit_regions(mem_size);
-               user_defined_memmap = 1;
-       }
-       return 0;
-}
-early_param("mem", parse_mem);
-
-#ifdef CONFIG_PROC_VMCORE
-/* elfcorehdr= specifies the location of elf core header
- * stored by the crashed kernel.
- */
-static int __init parse_elfcorehdr(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       elfcorehdr_addr = memparse(arg, &arg);
-       return 0;
-}
-early_param("elfcorehdr", parse_elfcorehdr);
-#endif /* CONFIG_PROC_VMCORE */
-
-/*
- * highmem=size forces highmem to be exactly 'size' bytes.
- * This works even on boxes that have no highmem otherwise.
- * This also works to reduce highmem size on bigger boxes.
- */
-static int __init parse_highmem(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT;
-       return 0;
-}
-early_param("highmem", parse_highmem);
-
-/*
- * vmalloc=size forces the vmalloc area to be exactly 'size'
- * bytes. This can be used to increase (or decrease) the
- * vmalloc area - the default is 128m.
- */
-static int __init parse_vmalloc(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       __VMALLOC_RESERVE = memparse(arg, &arg);
-       return 0;
-}
-early_param("vmalloc", parse_vmalloc);
-
-/*
- * reservetop=size reserves a hole at the top of the kernel address space which
- * a hypervisor can load into later.  Needed for dynamically loaded hypervisors,
- * so relocating the fixmap can be done before paging initialization.
- */
-static int __init parse_reservetop(char *arg)
-{
-       unsigned long address;
-
-       if (!arg)
-               return -EINVAL;
-
-       address = memparse(arg, &arg);
-       reserve_top_address(address);
-       return 0;
-}
-early_param("reservetop", parse_reservetop);
-
-/*
- * Determine low and high memory ranges:
- */
-unsigned long __init find_max_low_pfn(void)
-{
-       unsigned long max_low_pfn;
-
-       max_low_pfn = max_pfn;
-       if (max_low_pfn > MAXMEM_PFN) {
-               if (highmem_pages == -1)
-                       highmem_pages = max_pfn - MAXMEM_PFN;
-               if (highmem_pages + MAXMEM_PFN < max_pfn)
-                       max_pfn = MAXMEM_PFN + highmem_pages;
-               if (highmem_pages + MAXMEM_PFN > max_pfn) {
-                       printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages));
-                       highmem_pages = 0;
-               }
-               max_low_pfn = MAXMEM_PFN;
-#ifndef CONFIG_HIGHMEM
-               /* Maximum memory usable is what is directly addressable */
-               printk(KERN_WARNING "Warning only %ldMB will be used.\n",
-                                       MAXMEM>>20);
-               if (max_pfn > MAX_NONPAE_PFN)
-                       printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
-               else
-                       printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
-               max_pfn = MAXMEM_PFN;
-#else /* !CONFIG_HIGHMEM */
-#ifndef CONFIG_HIGHMEM64G
-               if (max_pfn > MAX_NONPAE_PFN) {
-                       max_pfn = MAX_NONPAE_PFN;
-                       printk(KERN_WARNING "Warning only 4GB will be used.\n");
-                       printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
-               }
-#endif /* !CONFIG_HIGHMEM64G */
-#endif /* !CONFIG_HIGHMEM */
-       } else {
-               if (highmem_pages == -1)
-                       highmem_pages = 0;
-#ifdef CONFIG_HIGHMEM
-               if (highmem_pages >= max_pfn) {
-                       printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
-                       highmem_pages = 0;
-               }
-               if (highmem_pages) {
-                       if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){
-                               printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages));
-                               highmem_pages = 0;
-                       }
-                       max_low_pfn -= highmem_pages;
-               }
-#else
-               if (highmem_pages)
-                       printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n");
-#endif
-       }
-       return max_low_pfn;
-}
-
-#define BIOS_LOWMEM_KILOBYTES 0x413
-
-/*
- * The BIOS places the EBDA/XBDA at the top of conventional
- * memory, and usually decreases the reported amount of
- * conventional memory (int 0x12) too. This also contains a
- * workaround for Dell systems that neglect to reserve EBDA.
- * The same workaround also avoids a problem with the AMD768MPX
- * chipset: reserve a page before VGA to prevent PCI prefetch
- * into it (errata #56). Usually the page is reserved anyways,
- * unless you have no PS/2 mouse plugged in.
- */
-static void __init reserve_ebda_region(void)
-{
-       unsigned int lowmem, ebda_addr;
-
-       /* To determine the position of the EBDA and the */
-       /* end of conventional memory, we need to look at */
-       /* the BIOS data area. In a paravirtual environment */
-       /* that area is absent. We'll just have to assume */
-       /* that the paravirt case can handle memory setup */
-       /* correctly, without our help. */
-       if (paravirt_enabled())
-               return;
-
-       /* end of low (conventional) memory */
-       lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES);
-       lowmem <<= 10;
-
-       /* start of EBDA area */
-       ebda_addr = get_bios_ebda();
-
-       /* Fixup: bios puts an EBDA in the top 64K segment */
-       /* of conventional memory, but does not adjust lowmem. */
-       if ((lowmem - ebda_addr) <= 0x10000)
-               lowmem = ebda_addr;
-
-       /* Fixup: bios does not report an EBDA at all. */
-       /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */
-       if ((ebda_addr == 0) && (lowmem >= 0x9f000))
-               lowmem = 0x9f000;
-
-       /* Paranoia: should never happen, but... */
-       if ((lowmem == 0) || (lowmem >= 0x100000))
-               lowmem = 0x9f000;
-
-       /* reserve all memory between lowmem and the 1MB mark */
-       reserve_bootmem(lowmem, 0x100000 - lowmem, BOOTMEM_DEFAULT);
-}
-
-#ifndef CONFIG_NEED_MULTIPLE_NODES
-static void __init setup_bootmem_allocator(void);
-static unsigned long __init setup_memory(void)
-{
-       /*
-        * partially used pages are not usable - thus
-        * we are rounding upwards:
-        */
-       min_low_pfn = PFN_UP(init_pg_tables_end);
-
-       max_low_pfn = find_max_low_pfn();
-
-#ifdef CONFIG_HIGHMEM
-       highstart_pfn = highend_pfn = max_pfn;
-       if (max_pfn > max_low_pfn) {
-               highstart_pfn = max_low_pfn;
-       }
-       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
-       num_physpages = max_low_pfn;
-       high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
-#endif
-#ifdef CONFIG_FLATMEM
-       max_mapnr = num_physpages;
-#endif
-       printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
-                       pages_to_mb(max_low_pfn));
-
-       setup_bootmem_allocator();
-
-       return max_low_pfn;
-}
-
-static void __init zone_sizes_init(void)
-{
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-       max_zone_pfns[ZONE_DMA] =
-               virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
-#ifdef CONFIG_HIGHMEM
-       max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
-       add_active_range(0, 0, highend_pfn);
-#else
-       add_active_range(0, 0, max_low_pfn);
-#endif
-
-       free_area_init_nodes(max_zone_pfns);
-}
-#else
-extern unsigned long __init setup_memory(void);
-extern void zone_sizes_init(void);
-#endif /* !CONFIG_NEED_MULTIPLE_NODES */
-
-static inline unsigned long long get_total_mem(void)
-{
-       unsigned long long total;
-
-       total = max_low_pfn - min_low_pfn;
-#ifdef CONFIG_HIGHMEM
-       total += highend_pfn - highstart_pfn;
-#endif
-
-       return total << PAGE_SHIFT;
-}
-
-#ifdef CONFIG_KEXEC
-static void __init reserve_crashkernel(void)
-{
-       unsigned long long total_mem;
-       unsigned long long crash_size, crash_base;
-       int ret;
-
-       total_mem = get_total_mem();
-
-       ret = parse_crashkernel(boot_command_line, total_mem,
-                       &crash_size, &crash_base);
-       if (ret == 0 && crash_size > 0) {
-               if (crash_base > 0) {
-                       printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
-                                       "for crashkernel (System RAM: %ldMB)\n",
-                                       (unsigned long)(crash_size >> 20),
-                                       (unsigned long)(crash_base >> 20),
-                                       (unsigned long)(total_mem >> 20));
-
-                       if (reserve_bootmem(crash_base, crash_size,
-                                       BOOTMEM_EXCLUSIVE) < 0) {
-                               printk(KERN_INFO "crashkernel reservation "
-                                       "failed - memory is in use\n");
-                               return;
-                       }
-
-                       crashk_res.start = crash_base;
-                       crashk_res.end   = crash_base + crash_size - 1;
-               } else
-                       printk(KERN_INFO "crashkernel reservation failed - "
-                                       "you have to specify a base address\n");
-       }
-}
-#else
-static inline void __init reserve_crashkernel(void)
-{}
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-
-static bool do_relocate_initrd = false;
-
-static void __init reserve_initrd(void)
-{
-       unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
-       unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
-       unsigned long ramdisk_end   = ramdisk_image + ramdisk_size;
-       unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT;
-       unsigned long ramdisk_here;
-
-       initrd_start = 0;
-
-       if (!boot_params.hdr.type_of_loader ||
-           !ramdisk_image || !ramdisk_size)
-               return;         /* No initrd provided by bootloader */
-
-       if (ramdisk_end < ramdisk_image) {
-               printk(KERN_ERR "initrd wraps around end of memory, "
-                      "disabling initrd\n");
-               return;
-       }
-       if (ramdisk_size >= end_of_lowmem/2) {
-               printk(KERN_ERR "initrd too large to handle, "
-                      "disabling initrd\n");
-               return;
-       }
-       if (ramdisk_end <= end_of_lowmem) {
-               /* All in lowmem, easy case */
-               reserve_bootmem(ramdisk_image, ramdisk_size, BOOTMEM_DEFAULT);
-               initrd_start = ramdisk_image + PAGE_OFFSET;
-               initrd_end = initrd_start+ramdisk_size;
-               return;
-       }
-
-       /* We need to move the initrd down into lowmem */
-       ramdisk_here = (end_of_lowmem - ramdisk_size) & PAGE_MASK;
-
-       /* Note: this includes all the lowmem currently occupied by
-          the initrd, we rely on that fact to keep the data intact. */
-       reserve_bootmem(ramdisk_here, ramdisk_size, BOOTMEM_DEFAULT);
-       initrd_start = ramdisk_here + PAGE_OFFSET;
-       initrd_end   = initrd_start + ramdisk_size;
-
-       do_relocate_initrd = true;
-}
-
-#define MAX_MAP_CHUNK  (NR_FIX_BTMAPS << PAGE_SHIFT)
-
-static void __init relocate_initrd(void)
-{
-       unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
-       unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
-       unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT;
-       unsigned long ramdisk_here;
-       unsigned long slop, clen, mapaddr;
-       char *p, *q;
-
-       if (!do_relocate_initrd)
-               return;
-
-       ramdisk_here = initrd_start - PAGE_OFFSET;
-
-       q = (char *)initrd_start;
-
-       /* Copy any lowmem portion of the initrd */
-       if (ramdisk_image < end_of_lowmem) {
-               clen = end_of_lowmem - ramdisk_image;
-               p = (char *)__va(ramdisk_image);
-               memcpy(q, p, clen);
-               q += clen;
-               ramdisk_image += clen;
-               ramdisk_size  -= clen;
-       }
-
-       /* Copy the highmem portion of the initrd */
-       while (ramdisk_size) {
-               slop = ramdisk_image & ~PAGE_MASK;
-               clen = ramdisk_size;
-               if (clen > MAX_MAP_CHUNK-slop)
-                       clen = MAX_MAP_CHUNK-slop;
-               mapaddr = ramdisk_image & PAGE_MASK;
-               p = early_ioremap(mapaddr, clen+slop);
-               memcpy(q, p+slop, clen);
-               early_iounmap(p, clen+slop);
-               q += clen;
-               ramdisk_image += clen;
-               ramdisk_size  -= clen;
-       }
-}
-
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-void __init setup_bootmem_allocator(void)
-{
-       unsigned long bootmap_size;
-       /*
-        * Initialize the boot-time allocator (with low memory only):
-        */
-       bootmap_size = init_bootmem(min_low_pfn, max_low_pfn);
-
-       register_bootmem_low_pages(max_low_pfn);
-
-       /*
-        * Reserve the bootmem bitmap itself as well. We do this in two
-        * steps (first step was init_bootmem()) because this catches
-        * the (very unlikely) case of us accidentally initializing the
-        * bootmem allocator with an invalid RAM area.
-        */
-       reserve_bootmem(__pa_symbol(_text), (PFN_PHYS(min_low_pfn) +
-                        bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text),
-                        BOOTMEM_DEFAULT);
-
-       /*
-        * reserve physical page 0 - it's a special BIOS page on many boxes,
-        * enabling clean reboots, SMP operation, laptop functions.
-        */
-       reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
-
-       /* reserve EBDA region */
-       reserve_ebda_region();
-
-#ifdef CONFIG_SMP
-       /*
-        * But first pinch a few for the stack/trampoline stuff
-        * FIXME: Don't need the extra page at 4K, but need to fix
-        * trampoline before removing it. (see the GDT stuff)
-        */
-       reserve_bootmem(PAGE_SIZE, PAGE_SIZE, BOOTMEM_DEFAULT);
-#endif
-#ifdef CONFIG_ACPI_SLEEP
-       /*
-        * Reserve low memory region for sleep support.
-        */
-       acpi_reserve_bootmem();
-#endif
-#ifdef CONFIG_X86_FIND_SMP_CONFIG
-       /*
-        * Find and reserve possible boot-time SMP configuration:
-        */
-       find_smp_config();
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-       reserve_initrd();
-#endif
-       numa_kva_reserve();
-       reserve_crashkernel();
-
-       reserve_ibft_region();
-}
-
-/*
- * The node 0 pgdat is initialized before all of these because
- * it's needed for bootmem.  node>0 pgdats have their virtual
- * space allocated before the pagetables are in place to access
- * them, so they can't be cleared then.
- *
- * This should all compile down to nothing when NUMA is off.
- */
-static void __init remapped_pgdat_init(void)
-{
-       int nid;
-
-       for_each_online_node(nid) {
-               if (nid != 0)
-                       memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
-       }
-}
-
-#ifdef CONFIG_MCA
-static void set_mca_bus(int x)
-{
-       MCA_bus = x;
-}
-#else
-static void set_mca_bus(int x) { }
-#endif
-
-/* Overridden in paravirt.c if CONFIG_PARAVIRT */
-char * __init __attribute__((weak)) memory_setup(void)
-{
-       return machine_specific_memory_setup();
-}
-
-#ifdef CONFIG_NUMA
-/*
- * In the golden day, when everything among i386 and x86_64 will be
- * integrated, this will not live here
- */
-void *x86_cpu_to_node_map_early_ptr;
-int x86_cpu_to_node_map_init[NR_CPUS] = {
-       [0 ... NR_CPUS-1] = NUMA_NO_NODE
-};
-DEFINE_PER_CPU(int, x86_cpu_to_node_map) = NUMA_NO_NODE;
-#endif
-
-/*
- * Determine if we were loaded by an EFI loader.  If so, then we have also been
- * passed the efi memmap, systab, etc., so we should use these data structures
- * for initialization.  Note, the efi init code path is determined by the
- * global efi_enabled. This allows the same kernel image to be used on existing
- * systems (with a traditional BIOS) as well as on EFI systems.
- */
-void __init setup_arch(char **cmdline_p)
-{
-       unsigned long max_low_pfn;
-
-       memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
-       pre_setup_arch_hook();
-       early_cpu_init();
-       early_ioremap_init();
-
-#ifdef CONFIG_EFI
-       if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
-                    "EL32", 4))
-               efi_enabled = 1;
-#endif
-
-       ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
-       screen_info = boot_params.screen_info;
-       edid_info = boot_params.edid_info;
-       apm_info.bios = boot_params.apm_bios_info;
-       ist_info = boot_params.ist_info;
-       saved_video_mode = boot_params.hdr.vid_mode;
-       if( boot_params.sys_desc_table.length != 0 ) {
-               set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
-               machine_id = boot_params.sys_desc_table.table[0];
-               machine_submodel_id = boot_params.sys_desc_table.table[1];
-               BIOS_revision = boot_params.sys_desc_table.table[2];
-       }
-       bootloader_type = boot_params.hdr.type_of_loader;
-
-#ifdef CONFIG_BLK_DEV_RAM
-       rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
-       rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
-       rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
-#endif
-       ARCH_SETUP
-
-       printk(KERN_INFO "BIOS-provided physical RAM map:\n");
-       print_memory_map(memory_setup());
-
-       copy_edd();
-
-       if (!boot_params.hdr.root_flags)
-               root_mountflags &= ~MS_RDONLY;
-       init_mm.start_code = (unsigned long) _text;
-       init_mm.end_code = (unsigned long) _etext;
-       init_mm.end_data = (unsigned long) _edata;
-       init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
-
-       code_resource.start = virt_to_phys(_text);
-       code_resource.end = virt_to_phys(_etext)-1;
-       data_resource.start = virt_to_phys(_etext);
-       data_resource.end = virt_to_phys(_edata)-1;
-       bss_resource.start = virt_to_phys(&__bss_start);
-       bss_resource.end = virt_to_phys(&__bss_stop)-1;
-
-       parse_early_param();
-
-       if (user_defined_memmap) {
-               printk(KERN_INFO "user-defined physical RAM map:\n");
-               print_memory_map("user");
-       }
-
-       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-       *cmdline_p = command_line;
-
-       if (efi_enabled)
-               efi_init();
-
-       /* update e820 for memory not covered by WB MTRRs */
-       propagate_e820_map();
-       mtrr_bp_init();
-       if (mtrr_trim_uncached_memory(max_pfn))
-               propagate_e820_map();
-
-       max_low_pfn = setup_memory();
-
-#ifdef CONFIG_KVM_CLOCK
-       kvmclock_init();
-#endif
-
-#ifdef CONFIG_VMI
-       /*
-        * Must be after max_low_pfn is determined, and before kernel
-        * pagetables are setup.
-        */
-       vmi_init();
-#endif
-       kvm_guest_init();
-
-       /*
-        * NOTE: before this point _nobody_ is allowed to allocate
-        * any memory using the bootmem allocator.  Although the
-        * allocator is now initialised only the first 8Mb of the kernel
-        * virtual address space has been mapped.  All allocations before
-        * paging_init() has completed must use the alloc_bootmem_low_pages()
-        * variant (which allocates DMA'able memory) and care must be taken
-        * not to exceed the 8Mb limit.
-        */
-
-#ifdef CONFIG_SMP
-       smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
-#endif
-       paging_init();
-
-       /*
-        * NOTE: On x86-32, only from this point on, fixmaps are ready for use.
-        */
-
-#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
-       if (init_ohci1394_dma_early)
-               init_ohci1394_dma_on_all_controllers();
-#endif
-
-       remapped_pgdat_init();
-       sparse_init();
-       zone_sizes_init();
-
-       /*
-        * NOTE: at this point the bootmem allocator is fully available.
-        */
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       relocate_initrd();
-#endif
-
-       paravirt_post_allocator_init();
-
-       dmi_scan_machine();
-
-       io_delay_init();
-
-#ifdef CONFIG_X86_SMP
-       /*
-        * setup to use the early static init tables during kernel startup
-        * X86_SMP will exclude sub-arches that don't deal well with it.
-        */
-       x86_cpu_to_apicid_early_ptr = (void *)x86_cpu_to_apicid_init;
-       x86_bios_cpu_apicid_early_ptr = (void *)x86_bios_cpu_apicid_init;
-#ifdef CONFIG_NUMA
-       x86_cpu_to_node_map_early_ptr = (void *)x86_cpu_to_node_map_init;
-#endif
-#endif
-
-#ifdef CONFIG_X86_GENERICARCH
-       generic_apic_probe();
-#endif
-
-#ifdef CONFIG_ACPI
-       /*
-        * Parse the ACPI tables for possible boot-time SMP configuration.
-        */
-       acpi_boot_table_init();
-#endif
-
-       early_quirks();
-
-#ifdef CONFIG_ACPI
-       acpi_boot_init();
-
-#if defined(CONFIG_SMP) && defined(CONFIG_X86_PC)
-       if (def_to_bigsmp)
-               printk(KERN_WARNING "More than 8 CPUs detected and "
-                       "CONFIG_X86_PC cannot handle it.\nUse "
-                       "CONFIG_X86_GENERICARCH or CONFIG_X86_BIGSMP.\n");
-#endif
-#endif
-#ifdef CONFIG_X86_LOCAL_APIC
-       if (smp_found_config)
-               get_smp_config();
-#endif
-
-       e820_register_memory();
-       e820_mark_nosave_regions();
-
-#ifdef CONFIG_VT
-#if defined(CONFIG_VGA_CONSOLE)
-       if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
-               conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
-       conswitchp = &dummy_con;
-#endif
-#endif
-}
-
-/*
- * Request address space for all standard resources
- *
- * This is called just before pcibios_init(), which is also a
- * subsys_initcall, but is linked in later (in arch/i386/pci/common.c).
- */
-static int __init request_standard_resources(void)
-{
-       int i;
-
-       printk(KERN_INFO "Setting up standard PCI resources\n");
-       init_iomem_resources(&code_resource, &data_resource, &bss_resource);
-
-       request_resource(&iomem_resource, &video_ram_resource);
-
-       /* request I/O space for devices used on all i[345]86 PCs */
-       for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
-               request_resource(&ioport_resource, &standard_io_resources[i]);
-       return 0;
-}
-
-subsys_initcall(request_standard_resources);
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
deleted file mode 100644 (file)
index 6dff128..0000000
+++ /dev/null
@@ -1,1194 +0,0 @@
-/*
- *  Copyright (C) 1995  Linus Torvalds
- */
-
-/*
- * This file handles the architecture-dependent parts of initialization
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/screen_info.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/initrd.h>
-#include <linux/highmem.h>
-#include <linux/bootmem.h>
-#include <linux/module.h>
-#include <asm/processor.h>
-#include <linux/console.h>
-#include <linux/seq_file.h>
-#include <linux/crash_dump.h>
-#include <linux/root_dev.h>
-#include <linux/pci.h>
-#include <asm/pci-direct.h>
-#include <linux/efi.h>
-#include <linux/acpi.h>
-#include <linux/kallsyms.h>
-#include <linux/edd.h>
-#include <linux/iscsi_ibft.h>
-#include <linux/mmzone.h>
-#include <linux/kexec.h>
-#include <linux/cpufreq.h>
-#include <linux/dmi.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <linux/sort.h>
-#include <linux/uaccess.h>
-#include <linux/init_ohci1394_dma.h>
-#include <linux/kvm_para.h>
-
-#include <asm/mtrr.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/vsyscall.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/msr.h>
-#include <asm/desc.h>
-#include <video/edid.h>
-#include <asm/e820.h>
-#include <asm/dma.h>
-#include <asm/gart.h>
-#include <asm/mpspec.h>
-#include <asm/mmu_context.h>
-#include <asm/proto.h>
-#include <asm/setup.h>
-#include <asm/numa.h>
-#include <asm/sections.h>
-#include <asm/dmi.h>
-#include <asm/cacheflush.h>
-#include <asm/mce.h>
-#include <asm/ds.h>
-#include <asm/topology.h>
-#include <asm/trampoline.h>
-#include <asm/pat.h>
-
-#include <mach_apic.h>
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define ARCH_SETUP
-#endif
-
-/*
- * Machine setup..
- */
-
-struct cpuinfo_x86 boot_cpu_data __read_mostly;
-EXPORT_SYMBOL(boot_cpu_data);
-
-__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata;
-
-unsigned long mmu_cr4_features;
-
-/* Boot loader ID as an integer, for the benefit of proc_dointvec */
-int bootloader_type;
-
-unsigned long saved_video_mode;
-
-int force_mwait __cpuinitdata;
-
-/*
- * Early DMI memory
- */
-int dmi_alloc_index;
-char dmi_alloc_data[DMI_MAX_DATA];
-
-/*
- * Setup options
- */
-struct screen_info screen_info;
-EXPORT_SYMBOL(screen_info);
-struct sys_desc_table_struct {
-       unsigned short length;
-       unsigned char table[0];
-};
-
-struct edid_info edid_info;
-EXPORT_SYMBOL_GPL(edid_info);
-
-extern int root_mountflags;
-
-char __initdata command_line[COMMAND_LINE_SIZE];
-
-static struct resource standard_io_resources[] = {
-       { .name = "dma1", .start = 0x00, .end = 0x1f,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "pic1", .start = 0x20, .end = 0x21,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "timer0", .start = 0x40, .end = 0x43,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "timer1", .start = 0x50, .end = 0x53,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "keyboard", .start = 0x60, .end = 0x60,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "keyboard", .start = 0x64, .end = 0x64,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "dma page reg", .start = 0x80, .end = 0x8f,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "pic2", .start = 0xa0, .end = 0xa1,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "dma2", .start = 0xc0, .end = 0xdf,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO },
-       { .name = "fpu", .start = 0xf0, .end = 0xff,
-               .flags = IORESOURCE_BUSY | IORESOURCE_IO }
-};
-
-#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
-
-static struct resource data_resource = {
-       .name = "Kernel data",
-       .start = 0,
-       .end = 0,
-       .flags = IORESOURCE_RAM,
-};
-static struct resource code_resource = {
-       .name = "Kernel code",
-       .start = 0,
-       .end = 0,
-       .flags = IORESOURCE_RAM,
-};
-static struct resource bss_resource = {
-       .name = "Kernel bss",
-       .start = 0,
-       .end = 0,
-       .flags = IORESOURCE_RAM,
-};
-
-static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
-
-#ifdef CONFIG_PROC_VMCORE
-/* elfcorehdr= specifies the location of elf core header
- * stored by the crashed kernel. This option will be passed
- * by kexec loader to the capture kernel.
- */
-static int __init setup_elfcorehdr(char *arg)
-{
-       char *end;
-       if (!arg)
-               return -EINVAL;
-       elfcorehdr_addr = memparse(arg, &end);
-       return end > arg ? 0 : -EINVAL;
-}
-early_param("elfcorehdr", setup_elfcorehdr);
-#endif
-
-#ifndef CONFIG_NUMA
-static void __init
-contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
-{
-       unsigned long bootmap_size, bootmap;
-
-       bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
-       bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
-                                PAGE_SIZE);
-       if (bootmap == -1L)
-               panic("Cannot find bootmem map of size %ld\n", bootmap_size);
-       bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
-       e820_register_active_regions(0, start_pfn, end_pfn);
-       free_bootmem_with_active_regions(0, end_pfn);
-       early_res_to_bootmem(0, end_pfn<<PAGE_SHIFT);
-       reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT);
-}
-#endif
-
-#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-struct edd edd;
-#ifdef CONFIG_EDD_MODULE
-EXPORT_SYMBOL(edd);
-#endif
-/**
- * copy_edd() - Copy the BIOS EDD information
- *              from boot_params into a safe place.
- *
- */
-static inline void copy_edd(void)
-{
-     memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer,
-           sizeof(edd.mbr_signature));
-     memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info));
-     edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries;
-     edd.edd_info_nr = boot_params.eddbuf_entries;
-}
-#else
-static inline void copy_edd(void)
-{
-}
-#endif
-
-#ifdef CONFIG_KEXEC
-static void __init reserve_crashkernel(void)
-{
-       unsigned long long total_mem;
-       unsigned long long crash_size, crash_base;
-       int ret;
-
-       total_mem = ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT;
-
-       ret = parse_crashkernel(boot_command_line, total_mem,
-                       &crash_size, &crash_base);
-       if (ret == 0 && crash_size) {
-               if (crash_base <= 0) {
-                       printk(KERN_INFO "crashkernel reservation failed - "
-                                       "you have to specify a base address\n");
-                       return;
-               }
-
-               if (reserve_bootmem(crash_base, crash_size,
-                                       BOOTMEM_EXCLUSIVE) < 0) {
-                       printk(KERN_INFO "crashkernel reservation failed - "
-                                       "memory is in use\n");
-                       return;
-               }
-
-               printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
-                               "for crashkernel (System RAM: %ldMB)\n",
-                               (unsigned long)(crash_size >> 20),
-                               (unsigned long)(crash_base >> 20),
-                               (unsigned long)(total_mem >> 20));
-               crashk_res.start = crash_base;
-               crashk_res.end   = crash_base + crash_size - 1;
-               insert_resource(&iomem_resource, &crashk_res);
-       }
-}
-#else
-static inline void __init reserve_crashkernel(void)
-{}
-#endif
-
-/* Overridden in paravirt.c if CONFIG_PARAVIRT */
-void __attribute__((weak)) __init memory_setup(void)
-{
-       machine_specific_memory_setup();
-}
-
-static void __init parse_setup_data(void)
-{
-       struct setup_data *data;
-       unsigned long pa_data;
-
-       if (boot_params.hdr.version < 0x0209)
-               return;
-       pa_data = boot_params.hdr.setup_data;
-       while (pa_data) {
-               data = early_ioremap(pa_data, PAGE_SIZE);
-               switch (data->type) {
-               default:
-                       break;
-               }
-#ifndef CONFIG_DEBUG_BOOT_PARAMS
-               free_early(pa_data, pa_data+sizeof(*data)+data->len);
-#endif
-               pa_data = data->next;
-               early_iounmap(data, PAGE_SIZE);
-       }
-}
-
-#ifdef CONFIG_PCI_MMCONFIG
-extern void __cpuinit fam10h_check_enable_mmcfg(void);
-extern void __init check_enable_amd_mmconf_dmi(void);
-#else
-void __cpuinit fam10h_check_enable_mmcfg(void)
-{
-}
-void __init check_enable_amd_mmconf_dmi(void)
-{
-}
-#endif
-
-/*
- * setup_arch - architecture-specific boot-time initializations
- *
- * Note: On x86_64, fixmaps are ready for use even before this is called.
- */
-void __init setup_arch(char **cmdline_p)
-{
-       unsigned i;
-
-       printk(KERN_INFO "Command line: %s\n", boot_command_line);
-
-       ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
-       screen_info = boot_params.screen_info;
-       edid_info = boot_params.edid_info;
-       saved_video_mode = boot_params.hdr.vid_mode;
-       bootloader_type = boot_params.hdr.type_of_loader;
-
-#ifdef CONFIG_BLK_DEV_RAM
-       rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
-       rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
-       rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
-#endif
-#ifdef CONFIG_EFI
-       if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
-                    "EL64", 4))
-               efi_enabled = 1;
-#endif
-
-       ARCH_SETUP
-
-       memory_setup();
-       copy_edd();
-
-       if (!boot_params.hdr.root_flags)
-               root_mountflags &= ~MS_RDONLY;
-       init_mm.start_code = (unsigned long) &_text;
-       init_mm.end_code = (unsigned long) &_etext;
-       init_mm.end_data = (unsigned long) &_edata;
-       init_mm.brk = (unsigned long) &_end;
-
-       code_resource.start = virt_to_phys(&_text);
-       code_resource.end = virt_to_phys(&_etext)-1;
-       data_resource.start = virt_to_phys(&_etext);
-       data_resource.end = virt_to_phys(&_edata)-1;
-       bss_resource.start = virt_to_phys(&__bss_start);
-       bss_resource.end = virt_to_phys(&__bss_stop)-1;
-
-       early_identify_cpu(&boot_cpu_data);
-
-       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-       *cmdline_p = command_line;
-
-       parse_setup_data();
-
-       parse_early_param();
-
-#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
-       if (init_ohci1394_dma_early)
-               init_ohci1394_dma_on_all_controllers();
-#endif
-
-       finish_e820_parsing();
-
-       /* after parse_early_param, so could debug it */
-       insert_resource(&iomem_resource, &code_resource);
-       insert_resource(&iomem_resource, &data_resource);
-       insert_resource(&iomem_resource, &bss_resource);
-
-       early_gart_iommu_check();
-
-       e820_register_active_regions(0, 0, -1UL);
-       /*
-        * partially used pages are not usable - thus
-        * we are rounding upwards:
-        */
-       end_pfn = e820_end_of_ram();
-       /* update e820 for memory not covered by WB MTRRs */
-       mtrr_bp_init();
-       if (mtrr_trim_uncached_memory(end_pfn)) {
-               e820_register_active_regions(0, 0, -1UL);
-               end_pfn = e820_end_of_ram();
-       }
-
-       num_physpages = end_pfn;
-
-       check_efer();
-
-       max_pfn_mapped = init_memory_mapping(0, (max_pfn_mapped << PAGE_SHIFT));
-       if (efi_enabled)
-               efi_init();
-
-       vsmp_init();
-
-       dmi_scan_machine();
-
-       io_delay_init();
-
-#ifdef CONFIG_KVM_CLOCK
-       kvmclock_init();
-#endif
-
-#ifdef CONFIG_SMP
-       /* setup to use the early static init tables during kernel startup */
-       x86_cpu_to_apicid_early_ptr = (void *)x86_cpu_to_apicid_init;
-       x86_bios_cpu_apicid_early_ptr = (void *)x86_bios_cpu_apicid_init;
-#ifdef CONFIG_NUMA
-       x86_cpu_to_node_map_early_ptr = (void *)x86_cpu_to_node_map_init;
-#endif
-#endif
-
-#ifdef CONFIG_ACPI
-       /*
-        * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
-        * Call this early for SRAT node setup.
-        */
-       acpi_boot_table_init();
-#endif
-
-       /* How many end-of-memory variables you have, grandma! */
-       max_low_pfn = end_pfn;
-       max_pfn = end_pfn;
-       high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
-
-       /* Remove active ranges so rediscovery with NUMA-awareness happens */
-       remove_all_active_ranges();
-
-#ifdef CONFIG_ACPI_NUMA
-       /*
-        * Parse SRAT to discover nodes.
-        */
-       acpi_numa_init();
-#endif
-
-#ifdef CONFIG_NUMA
-       numa_initmem_init(0, end_pfn);
-#else
-       contig_initmem_init(0, end_pfn);
-#endif
-
-       dma32_reserve_bootmem();
-
-#ifdef CONFIG_ACPI_SLEEP
-       /*
-        * Reserve low memory region for sleep support.
-        */
-       acpi_reserve_bootmem();
-#endif
-
-       if (efi_enabled)
-               efi_reserve_bootmem();
-
-       /*
-       * Find and reserve possible boot-time SMP configuration:
-       */
-       find_smp_config();
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
-               unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
-               unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
-               unsigned long ramdisk_end   = ramdisk_image + ramdisk_size;
-               unsigned long end_of_mem    = end_pfn << PAGE_SHIFT;
-
-               if (ramdisk_end <= end_of_mem) {
-                       /*
-                        * don't need to reserve again, already reserved early
-                        * in x86_64_start_kernel, and early_res_to_bootmem
-                        * convert that to reserved in bootmem
-                        */
-                       initrd_start = ramdisk_image + PAGE_OFFSET;
-                       initrd_end = initrd_start+ramdisk_size;
-               } else {
-                       free_bootmem(ramdisk_image, ramdisk_size);
-                       printk(KERN_ERR "initrd extends beyond end of memory "
-                              "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-                              ramdisk_end, end_of_mem);
-                       initrd_start = 0;
-               }
-       }
-#endif
-       reserve_crashkernel();
-
-       reserve_ibft_region();
-
-       paging_init();
-       map_vsyscall();
-
-       early_quirks();
-
-#ifdef CONFIG_ACPI
-       /*
-        * Read APIC and some other early information from ACPI tables.
-        */
-       acpi_boot_init();
-#endif
-
-       init_cpu_to_node();
-
-       /*
-        * get boot-time SMP configuration:
-        */
-       if (smp_found_config)
-               get_smp_config();
-       init_apic_mappings();
-       ioapic_init_mappings();
-
-       kvm_guest_init();
-
-       /*
-        * We trust e820 completely. No explicit ROM probing in memory.
-        */
-       e820_reserve_resources();
-       e820_mark_nosave_regions();
-
-       /* request I/O space for devices used on all i[345]86 PCs */
-       for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
-               request_resource(&ioport_resource, &standard_io_resources[i]);
-
-       e820_setup_gap();
-
-#ifdef CONFIG_VT
-#if defined(CONFIG_VGA_CONSOLE)
-       if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
-               conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
-       conswitchp = &dummy_con;
-#endif
-#endif
-
-       /* do this before identify_cpu for boot cpu */
-       check_enable_amd_mmconf_dmi();
-}
-
-static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
-{
-       unsigned int *v;
-
-       if (c->extended_cpuid_level < 0x80000004)
-               return 0;
-
-       v = (unsigned int *) c->x86_model_id;
-       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
-       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
-       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-       c->x86_model_id[48] = 0;
-       return 1;
-}
-
-
-static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
-{
-       unsigned int n, dummy, eax, ebx, ecx, edx;
-
-       n = c->extended_cpuid_level;
-
-       if (n >= 0x80000005) {
-               cpuid(0x80000005, &dummy, &ebx, &ecx, &edx);
-               printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), "
-                      "D cache %dK (%d bytes/line)\n",
-                      edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
-               c->x86_cache_size = (ecx>>24) + (edx>>24);
-               /* On K8 L1 TLB is inclusive, so don't count it */
-               c->x86_tlbsize = 0;
-       }
-
-       if (n >= 0x80000006) {
-               cpuid(0x80000006, &dummy, &ebx, &ecx, &edx);
-               ecx = cpuid_ecx(0x80000006);
-               c->x86_cache_size = ecx >> 16;
-               c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff);
-
-               printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-               c->x86_cache_size, ecx & 0xFF);
-       }
-       if (n >= 0x80000008) {
-               cpuid(0x80000008, &eax, &dummy, &dummy, &dummy);
-               c->x86_virt_bits = (eax >> 8) & 0xff;
-               c->x86_phys_bits = eax & 0xff;
-       }
-}
-
-#ifdef CONFIG_NUMA
-static int __cpuinit nearby_node(int apicid)
-{
-       int i, node;
-
-       for (i = apicid - 1; i >= 0; i--) {
-               node = apicid_to_node[i];
-               if (node != NUMA_NO_NODE && node_online(node))
-                       return node;
-       }
-       for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
-               node = apicid_to_node[i];
-               if (node != NUMA_NO_NODE && node_online(node))
-                       return node;
-       }
-       return first_node(node_online_map); /* Shouldn't happen */
-}
-#endif
-
-/*
- * On a AMD dual core setup the lower bits of the APIC id distingush the cores.
- * Assumes number of cores is a power of two.
- */
-static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned bits;
-#ifdef CONFIG_NUMA
-       int cpu = smp_processor_id();
-       int node = 0;
-       unsigned apicid = hard_smp_processor_id();
-#endif
-       bits = c->x86_coreid_bits;
-
-       /* Low order bits define the core id (index of core in socket) */
-       c->cpu_core_id = c->initial_apicid & ((1 << bits)-1);
-       /* Convert the initial APIC ID into the socket ID */
-       c->phys_proc_id = c->initial_apicid >> bits;
-
-#ifdef CONFIG_NUMA
-       node = c->phys_proc_id;
-       if (apicid_to_node[apicid] != NUMA_NO_NODE)
-               node = apicid_to_node[apicid];
-       if (!node_online(node)) {
-               /* Two possibilities here:
-                  - The CPU is missing memory and no node was created.
-                  In that case try picking one from a nearby CPU
-                  - The APIC IDs differ from the HyperTransport node IDs
-                  which the K8 northbridge parsing fills in.
-                  Assume they are all increased by a constant offset,
-                  but in the same order as the HT nodeids.
-                  If that doesn't result in a usable node fall back to the
-                  path for the previous case.  */
-
-               int ht_nodeid = c->initial_apicid;
-
-               if (ht_nodeid >= 0 &&
-                   apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
-                       node = apicid_to_node[ht_nodeid];
-               /* Pick a nearby node */
-               if (!node_online(node))
-                       node = nearby_node(apicid);
-       }
-       numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
-#endif
-#endif
-}
-
-static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       unsigned bits, ecx;
-
-       /* Multi core CPU? */
-       if (c->extended_cpuid_level < 0x80000008)
-               return;
-
-       ecx = cpuid_ecx(0x80000008);
-
-       c->x86_max_cores = (ecx & 0xff) + 1;
-
-       /* CPU telling us the core id bits shift? */
-       bits = (ecx >> 12) & 0xF;
-
-       /* Otherwise recompute */
-       if (bits == 0) {
-               while ((1 << bits) < c->x86_max_cores)
-                       bits++;
-       }
-
-       c->x86_coreid_bits = bits;
-
-#endif
-}
-
-#define ENABLE_C1E_MASK                0x18000000
-#define CPUID_PROCESSOR_SIGNATURE      1
-#define CPUID_XFAM             0x0ff00000
-#define CPUID_XFAM_K8          0x00000000
-#define CPUID_XFAM_10H         0x00100000
-#define CPUID_XFAM_11H         0x00200000
-#define CPUID_XMOD             0x000f0000
-#define CPUID_XMOD_REV_F       0x00040000
-
-/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
-static __cpuinit int amd_apic_timer_broken(void)
-{
-       u32 lo, hi, eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
-
-       switch (eax & CPUID_XFAM) {
-       case CPUID_XFAM_K8:
-               if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
-                       break;
-       case CPUID_XFAM_10H:
-       case CPUID_XFAM_11H:
-               rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
-               if (lo & ENABLE_C1E_MASK)
-                       return 1;
-               break;
-       default:
-               /* err on the side of caution */
-               return 1;
-       }
-       return 0;
-}
-
-static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
-{
-       early_init_amd_mc(c);
-
-       /* c->x86_power is 8000_0007 edx. Bit 8 is constant TSC */
-       if (c->x86_power & (1<<8))
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-}
-
-static void __cpuinit init_amd(struct cpuinfo_x86 *c)
-{
-       unsigned level;
-
-#ifdef CONFIG_SMP
-       unsigned long value;
-
-       /*
-        * Disable TLB flush filter by setting HWCR.FFDIS on K8
-        * bit 6 of msr C001_0015
-        *
-        * Errata 63 for SH-B3 steppings
-        * Errata 122 for all steppings (F+ have it disabled by default)
-        */
-       if (c->x86 == 15) {
-               rdmsrl(MSR_K8_HWCR, value);
-               value |= 1 << 6;
-               wrmsrl(MSR_K8_HWCR, value);
-       }
-#endif
-
-       /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
-          3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-       clear_cpu_cap(c, 0*32+31);
-
-       /* On C+ stepping K8 rep microcode works well for copy/memset */
-       level = cpuid_eax(1);
-       if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) ||
-                            level >= 0x0f58))
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-       if (c->x86 == 0x10 || c->x86 == 0x11)
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-
-       /* Enable workaround for FXSAVE leak */
-       if (c->x86 >= 6)
-               set_cpu_cap(c, X86_FEATURE_FXSAVE_LEAK);
-
-       level = get_model_name(c);
-       if (!level) {
-               switch (c->x86) {
-               case 15:
-                       /* Should distinguish Models here, but this is only
-                          a fallback anyways. */
-                       strcpy(c->x86_model_id, "Hammer");
-                       break;
-               }
-       }
-       display_cacheinfo(c);
-
-       /* Multi core CPU? */
-       if (c->extended_cpuid_level >= 0x80000008)
-               amd_detect_cmp(c);
-
-       if (c->extended_cpuid_level >= 0x80000006 &&
-               (cpuid_edx(0x80000006) & 0xf000))
-               num_cache_leaves = 4;
-       else
-               num_cache_leaves = 3;
-
-       if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
-               set_cpu_cap(c, X86_FEATURE_K8);
-
-       /* MFENCE stops RDTSC speculation */
-       set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
-
-       if (c->x86 == 0x10)
-               fam10h_check_enable_mmcfg();
-
-       if (amd_apic_timer_broken())
-               disable_apic_timer = 1;
-
-       if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
-               unsigned long long tseg;
-
-               /*
-                * Split up direct mapping around the TSEG SMM area.
-                * Don't do it for gbpages because there seems very little
-                * benefit in doing so.
-                */
-               if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg) &&
-               (tseg >> PMD_SHIFT) < (max_pfn_mapped >> (PMD_SHIFT-PAGE_SHIFT)))
-                       set_memory_4k((unsigned long)__va(tseg), 1);
-       }
-}
-
-void __cpuinit detect_ht(struct cpuinfo_x86 *c)
-{
-#ifdef CONFIG_SMP
-       u32 eax, ebx, ecx, edx;
-       int index_msb, core_bits;
-
-       cpuid(1, &eax, &ebx, &ecx, &edx);
-
-
-       if (!cpu_has(c, X86_FEATURE_HT))
-               return;
-       if (cpu_has(c, X86_FEATURE_CMP_LEGACY))
-               goto out;
-
-       smp_num_siblings = (ebx & 0xff0000) >> 16;
-
-       if (smp_num_siblings == 1) {
-               printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-       } else if (smp_num_siblings > 1) {
-
-               if (smp_num_siblings > NR_CPUS) {
-                       printk(KERN_WARNING "CPU: Unsupported number of "
-                              "siblings %d", smp_num_siblings);
-                       smp_num_siblings = 1;
-                       return;
-               }
-
-               index_msb = get_count_order(smp_num_siblings);
-               c->phys_proc_id = phys_pkg_id(index_msb);
-
-               smp_num_siblings = smp_num_siblings / c->x86_max_cores;
-
-               index_msb = get_count_order(smp_num_siblings);
-
-               core_bits = get_count_order(c->x86_max_cores);
-
-               c->cpu_core_id = phys_pkg_id(index_msb) &
-                                              ((1 << core_bits) - 1);
-       }
-out:
-       if ((c->x86_max_cores * smp_num_siblings) > 1) {
-               printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-                      c->phys_proc_id);
-               printk(KERN_INFO  "CPU: Processor Core ID: %d\n",
-                      c->cpu_core_id);
-       }
-
-#endif
-}
-
-/*
- * find out the number of processor cores on the die
- */
-static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
-{
-       unsigned int eax, t;
-
-       if (c->cpuid_level < 4)
-               return 1;
-
-       cpuid_count(4, 0, &eax, &t, &t, &t);
-
-       if (eax & 0x1f)
-               return ((eax >> 26) + 1);
-       else
-               return 1;
-}
-
-static void __cpuinit srat_detect_node(void)
-{
-#ifdef CONFIG_NUMA
-       unsigned node;
-       int cpu = smp_processor_id();
-       int apicid = hard_smp_processor_id();
-
-       /* Don't do the funky fallback heuristics the AMD version employs
-          for now. */
-       node = apicid_to_node[apicid];
-       if (node == NUMA_NO_NODE || !node_online(node))
-               node = first_node(node_online_map);
-       numa_set_node(cpu, node);
-
-       printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node);
-#endif
-}
-
-static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
-{
-       if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
-           (c->x86 == 0x6 && c->x86_model >= 0x0e))
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-}
-
-static void __cpuinit init_intel(struct cpuinfo_x86 *c)
-{
-       /* Cache sizes */
-       unsigned n;
-
-       init_intel_cacheinfo(c);
-       if (c->cpuid_level > 9) {
-               unsigned eax = cpuid_eax(10);
-               /* Check for version and the number of counters */
-               if ((eax & 0xff) && (((eax>>8) & 0xff) > 1))
-                       set_cpu_cap(c, X86_FEATURE_ARCH_PERFMON);
-       }
-
-       if (cpu_has_ds) {
-               unsigned int l1, l2;
-               rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
-               if (!(l1 & (1<<11)))
-                       set_cpu_cap(c, X86_FEATURE_BTS);
-               if (!(l1 & (1<<12)))
-                       set_cpu_cap(c, X86_FEATURE_PEBS);
-       }
-
-
-       if (cpu_has_bts)
-               ds_init_intel(c);
-
-       n = c->extended_cpuid_level;
-       if (n >= 0x80000008) {
-               unsigned eax = cpuid_eax(0x80000008);
-               c->x86_virt_bits = (eax >> 8) & 0xff;
-               c->x86_phys_bits = eax & 0xff;
-               /* CPUID workaround for Intel 0F34 CPU */
-               if (c->x86_vendor == X86_VENDOR_INTEL &&
-                   c->x86 == 0xF && c->x86_model == 0x3 &&
-                   c->x86_mask == 0x4)
-                       c->x86_phys_bits = 36;
-       }
-
-       if (c->x86 == 15)
-               c->x86_cache_alignment = c->x86_clflush_size * 2;
-       if (c->x86 == 6)
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-       c->x86_max_cores = intel_num_cpu_cores(c);
-
-       srat_detect_node();
-}
-
-static void __cpuinit early_init_centaur(struct cpuinfo_x86 *c)
-{
-       if (c->x86 == 0x6 && c->x86_model >= 0xf)
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-}
-
-static void __cpuinit init_centaur(struct cpuinfo_x86 *c)
-{
-       /* Cache sizes */
-       unsigned n;
-
-       n = c->extended_cpuid_level;
-       if (n >= 0x80000008) {
-               unsigned eax = cpuid_eax(0x80000008);
-               c->x86_virt_bits = (eax >> 8) & 0xff;
-               c->x86_phys_bits = eax & 0xff;
-       }
-
-       if (c->x86 == 0x6 && c->x86_model >= 0xf) {
-               c->x86_cache_alignment = c->x86_clflush_size * 2;
-               set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
-               set_cpu_cap(c, X86_FEATURE_REP_GOOD);
-       }
-       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
-}
-
-static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
-{
-       char *v = c->x86_vendor_id;
-
-       if (!strcmp(v, "AuthenticAMD"))
-               c->x86_vendor = X86_VENDOR_AMD;
-       else if (!strcmp(v, "GenuineIntel"))
-               c->x86_vendor = X86_VENDOR_INTEL;
-       else if (!strcmp(v, "CentaurHauls"))
-               c->x86_vendor = X86_VENDOR_CENTAUR;
-       else
-               c->x86_vendor = X86_VENDOR_UNKNOWN;
-}
-
-/* Do some early cpuid on the boot CPU to get some parameter that are
-   needed before check_bugs. Everything advanced is in identify_cpu
-   below. */
-static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
-{
-       u32 tfms, xlvl;
-
-       c->loops_per_jiffy = loops_per_jiffy;
-       c->x86_cache_size = -1;
-       c->x86_vendor = X86_VENDOR_UNKNOWN;
-       c->x86_model = c->x86_mask = 0; /* So far unknown... */
-       c->x86_vendor_id[0] = '\0'; /* Unset */
-       c->x86_model_id[0] = '\0';  /* Unset */
-       c->x86_clflush_size = 64;
-       c->x86_cache_alignment = c->x86_clflush_size;
-       c->x86_max_cores = 1;
-       c->x86_coreid_bits = 0;
-       c->extended_cpuid_level = 0;
-       memset(&c->x86_capability, 0, sizeof c->x86_capability);
-
-       /* Get vendor name */
-       cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
-             (unsigned int *)&c->x86_vendor_id[0],
-             (unsigned int *)&c->x86_vendor_id[8],
-             (unsigned int *)&c->x86_vendor_id[4]);
-
-       get_cpu_vendor(c);
-
-       /* Initialize the standard set of capabilities */
-       /* Note that the vendor-specific code below might override */
-
-       /* Intel-defined flags: level 0x00000001 */
-       if (c->cpuid_level >= 0x00000001) {
-               __u32 misc;
-               cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4],
-                     &c->x86_capability[0]);
-               c->x86 = (tfms >> 8) & 0xf;
-               c->x86_model = (tfms >> 4) & 0xf;
-               c->x86_mask = tfms & 0xf;
-               if (c->x86 == 0xf)
-                       c->x86 += (tfms >> 20) & 0xff;
-               if (c->x86 >= 0x6)
-                       c->x86_model += ((tfms >> 16) & 0xF) << 4;
-               if (test_cpu_cap(c, X86_FEATURE_CLFLSH))
-                       c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
-       } else {
-               /* Have CPUID level 0 only - unheard of */
-               c->x86 = 4;
-       }
-
-       c->initial_apicid = (cpuid_ebx(1) >> 24) & 0xff;
-#ifdef CONFIG_SMP
-       c->phys_proc_id = c->initial_apicid;
-#endif
-       /* AMD-defined flags: level 0x80000001 */
-       xlvl = cpuid_eax(0x80000000);
-       c->extended_cpuid_level = xlvl;
-       if ((xlvl & 0xffff0000) == 0x80000000) {
-               if (xlvl >= 0x80000001) {
-                       c->x86_capability[1] = cpuid_edx(0x80000001);
-                       c->x86_capability[6] = cpuid_ecx(0x80000001);
-               }
-               if (xlvl >= 0x80000004)
-                       get_model_name(c); /* Default name */
-       }
-
-       /* Transmeta-defined flags: level 0x80860001 */
-       xlvl = cpuid_eax(0x80860000);
-       if ((xlvl & 0xffff0000) == 0x80860000) {
-               /* Don't set x86_cpuid_level here for now to not confuse. */
-               if (xlvl >= 0x80860001)
-                       c->x86_capability[2] = cpuid_edx(0x80860001);
-       }
-
-       c->extended_cpuid_level = cpuid_eax(0x80000000);
-       if (c->extended_cpuid_level >= 0x80000007)
-               c->x86_power = cpuid_edx(0x80000007);
-
-       switch (c->x86_vendor) {
-       case X86_VENDOR_AMD:
-               early_init_amd(c);
-               break;
-       case X86_VENDOR_INTEL:
-               early_init_intel(c);
-               break;
-       case X86_VENDOR_CENTAUR:
-               early_init_centaur(c);
-               break;
-       }
-
-       validate_pat_support(c);
-}
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
-{
-       int i;
-
-       early_identify_cpu(c);
-
-       init_scattered_cpuid_features(c);
-
-       c->apicid = phys_pkg_id(0);
-
-       /*
-        * Vendor-specific initialization.  In this section we
-        * canonicalize the feature flags, meaning if there are
-        * features a certain CPU supports which CPUID doesn't
-        * tell us, CPUID claiming incorrect flags, or other bugs,
-        * we handle them here.
-        *
-        * At the end of this section, c->x86_capability better
-        * indicate the features this CPU genuinely supports!
-        */
-       switch (c->x86_vendor) {
-       case X86_VENDOR_AMD:
-               init_amd(c);
-               break;
-
-       case X86_VENDOR_INTEL:
-               init_intel(c);
-               break;
-
-       case X86_VENDOR_CENTAUR:
-               init_centaur(c);
-               break;
-
-       case X86_VENDOR_UNKNOWN:
-       default:
-               display_cacheinfo(c);
-               break;
-       }
-
-       detect_ht(c);
-
-       /*
-        * On SMP, boot_cpu_data holds the common feature set between
-        * all CPUs; so make sure that we indicate which features are
-        * common between the CPUs.  The first time this routine gets
-        * executed, c == &boot_cpu_data.
-        */
-       if (c != &boot_cpu_data) {
-               /* AND the already accumulated flags with these */
-               for (i = 0; i < NCAPINTS; i++)
-                       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
-       mcheck_init(c);
-#endif
-       select_idle_routine(c);
-
-#ifdef CONFIG_NUMA
-       numa_add_cpu(smp_processor_id());
-#endif
-
-}
-
-void __cpuinit identify_boot_cpu(void)
-{
-       identify_cpu(&boot_cpu_data);
-}
-
-void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
-{
-       BUG_ON(c == &boot_cpu_data);
-       identify_cpu(c);
-       mtrr_ap_init();
-}
-
-static __init int setup_noclflush(char *arg)
-{
-       setup_clear_cpu_cap(X86_FEATURE_CLFLSH);
-       return 1;
-}
-__setup("noclflush", setup_noclflush);
-
-void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
-{
-       if (c->x86_model_id[0])
-               printk(KERN_CONT "%s", c->x86_model_id);
-
-       if (c->x86_mask || c->cpuid_level >= 0)
-               printk(KERN_CONT " stepping %02x\n", c->x86_mask);
-       else
-               printk(KERN_CONT "\n");
-}
-
-static __init int setup_disablecpuid(char *arg)
-{
-       int bit;
-       if (get_option(&arg, &bit) && bit < NCAPINTS*32)
-               setup_clear_cpu_cap(bit);
-       else
-               return 0;
-       return 1;
-}
-__setup("clearcpuid=", setup_disablecpuid);
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
new file mode 100644 (file)
index 0000000..cac6843
--- /dev/null
@@ -0,0 +1,399 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/percpu.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
+#include <asm/smp.h>
+#include <asm/percpu.h>
+#include <asm/sections.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/topology.h>
+#include <asm/mpspec.h>
+#include <asm/apicdef.h>
+#include <asm/highmem.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+unsigned int num_processors;
+unsigned disabled_cpus __cpuinitdata;
+/* Processor that is doing the boot up */
+unsigned int boot_cpu_physical_apicid = -1U;
+unsigned int max_physical_apicid;
+EXPORT_SYMBOL(boot_cpu_physical_apicid);
+
+/* Bitmask of physically existing CPUs */
+physid_mask_t phys_cpu_present_map;
+#endif
+
+/* map cpu index to physical APIC ID */
+DEFINE_EARLY_PER_CPU(u16, x86_cpu_to_apicid, BAD_APICID);
+DEFINE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid, BAD_APICID);
+EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);
+EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+#define        X86_64_NUMA     1
+
+/* map cpu index to node index */
+DEFINE_EARLY_PER_CPU(int, x86_cpu_to_node_map, NUMA_NO_NODE);
+EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_node_map);
+
+/* which logical CPUs are on which nodes */
+cpumask_t *node_to_cpumask_map;
+EXPORT_SYMBOL(node_to_cpumask_map);
+
+/* setup node_to_cpumask_map */
+static void __init setup_node_to_cpumask_map(void);
+
+#else
+static inline void setup_node_to_cpumask_map(void) { }
+#endif
+
+#if defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) && defined(CONFIG_X86_SMP)
+/*
+ * Copy data used in early init routines from the initial arrays to the
+ * per cpu data areas.  These arrays then become expendable and the
+ * *_early_ptr's are zeroed indicating that the static arrays are gone.
+ */
+static void __init setup_per_cpu_maps(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               per_cpu(x86_cpu_to_apicid, cpu) =
+                               early_per_cpu_map(x86_cpu_to_apicid, cpu);
+               per_cpu(x86_bios_cpu_apicid, cpu) =
+                               early_per_cpu_map(x86_bios_cpu_apicid, cpu);
+#ifdef X86_64_NUMA
+               per_cpu(x86_cpu_to_node_map, cpu) =
+                               early_per_cpu_map(x86_cpu_to_node_map, cpu);
+#endif
+       }
+
+       /* indicate the early static arrays will soon be gone */
+       early_per_cpu_ptr(x86_cpu_to_apicid) = NULL;
+       early_per_cpu_ptr(x86_bios_cpu_apicid) = NULL;
+#ifdef X86_64_NUMA
+       early_per_cpu_ptr(x86_cpu_to_node_map) = NULL;
+#endif
+}
+
+#ifdef CONFIG_HAVE_CPUMASK_OF_CPU_MAP
+cpumask_t *cpumask_of_cpu_map __read_mostly;
+EXPORT_SYMBOL(cpumask_of_cpu_map);
+
+/* requires nr_cpu_ids to be initialized */
+static void __init setup_cpumask_of_cpu(void)
+{
+       int i;
+
+       /* alloc_bootmem zeroes memory */
+       cpumask_of_cpu_map = alloc_bootmem_low(sizeof(cpumask_t) * nr_cpu_ids);
+       for (i = 0; i < nr_cpu_ids; i++)
+               cpu_set(i, cpumask_of_cpu_map[i]);
+}
+#else
+static inline void setup_cpumask_of_cpu(void) { }
+#endif
+
+#ifdef CONFIG_X86_32
+/*
+ * Great future not-so-futuristic plan: make i386 and x86_64 do it
+ * the same way
+ */
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+static inline void setup_cpu_pda_map(void) { }
+
+#elif !defined(CONFIG_SMP)
+static inline void setup_cpu_pda_map(void) { }
+
+#else /* CONFIG_SMP && CONFIG_X86_64 */
+
+/*
+ * Allocate cpu_pda pointer table and array via alloc_bootmem.
+ */
+static void __init setup_cpu_pda_map(void)
+{
+       char *pda;
+       struct x8664_pda **new_cpu_pda;
+       unsigned long size;
+       int cpu;
+
+       size = roundup(sizeof(struct x8664_pda), cache_line_size());
+
+       /* allocate cpu_pda array and pointer table */
+       {
+               unsigned long tsize = nr_cpu_ids * sizeof(void *);
+               unsigned long asize = size * (nr_cpu_ids - 1);
+
+               tsize = roundup(tsize, cache_line_size());
+               new_cpu_pda = alloc_bootmem(tsize + asize);
+               pda = (char *)new_cpu_pda + tsize;
+       }
+
+       /* initialize pointer table to static pda's */
+       for_each_possible_cpu(cpu) {
+               if (cpu == 0) {
+                       /* leave boot cpu pda in place */
+                       new_cpu_pda[0] = cpu_pda(0);
+                       continue;
+               }
+               new_cpu_pda[cpu] = (struct x8664_pda *)pda;
+               new_cpu_pda[cpu]->in_bootmem = 1;
+               pda += size;
+       }
+
+       /* point to new pointer table */
+       _cpu_pda = new_cpu_pda;
+}
+#endif
+
+/*
+ * Great future plan:
+ * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
+ * Always point %gs to its beginning
+ */
+void __init setup_per_cpu_areas(void)
+{
+       ssize_t size = PERCPU_ENOUGH_ROOM;
+       char *ptr;
+       int cpu;
+
+       /* Setup cpu_pda map */
+       setup_cpu_pda_map();
+
+       /* Copy section for each CPU (we discard the original) */
+       size = PERCPU_ENOUGH_ROOM;
+       printk(KERN_INFO "PERCPU: Allocating %zd bytes of per cpu data\n",
+                         size);
+
+       for_each_possible_cpu(cpu) {
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+               ptr = alloc_bootmem_pages(size);
+#else
+               int node = early_cpu_to_node(cpu);
+               if (!node_online(node) || !NODE_DATA(node)) {
+                       ptr = alloc_bootmem_pages(size);
+                       printk(KERN_INFO
+                              "cpu %d has no node %d or node-local memory\n",
+                               cpu, node);
+               }
+               else
+                       ptr = alloc_bootmem_pages_node(NODE_DATA(node), size);
+#endif
+               per_cpu_offset(cpu) = ptr - __per_cpu_start;
+               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+
+       }
+
+       printk(KERN_DEBUG "NR_CPUS: %d, nr_cpu_ids: %d, nr_node_ids %d\n",
+               NR_CPUS, nr_cpu_ids, nr_node_ids);
+
+       /* Setup percpu data maps */
+       setup_per_cpu_maps();
+
+       /* Setup node to cpumask map */
+       setup_node_to_cpumask_map();
+
+       /* Setup cpumask_of_cpu map */
+       setup_cpumask_of_cpu();
+}
+
+#endif
+
+#ifdef X86_64_NUMA
+
+/*
+ * Allocate node_to_cpumask_map based on number of available nodes
+ * Requires node_possible_map to be valid.
+ *
+ * Note: node_to_cpumask() is not valid until after this is done.
+ */
+static void __init setup_node_to_cpumask_map(void)
+{
+       unsigned int node, num = 0;
+       cpumask_t *map;
+
+       /* setup nr_node_ids if not done yet */
+       if (nr_node_ids == MAX_NUMNODES) {
+               for_each_node_mask(node, node_possible_map)
+                       num = node;
+               nr_node_ids = num + 1;
+       }
+
+       /* allocate the map */
+       map = alloc_bootmem_low(nr_node_ids * sizeof(cpumask_t));
+
+       Dprintk(KERN_DEBUG "Node to cpumask map at %p for %d nodes\n",
+               map, nr_node_ids);
+
+       /* node_to_cpumask() will now work */
+       node_to_cpumask_map = map;
+}
+
+void __cpuinit numa_set_node(int cpu, int node)
+{
+       int *cpu_to_node_map = early_per_cpu_ptr(x86_cpu_to_node_map);
+
+       if (cpu_pda(cpu) && node != NUMA_NO_NODE)
+               cpu_pda(cpu)->nodenumber = node;
+
+       if (cpu_to_node_map)
+               cpu_to_node_map[cpu] = node;
+
+       else if (per_cpu_offset(cpu))
+               per_cpu(x86_cpu_to_node_map, cpu) = node;
+
+       else
+               Dprintk(KERN_INFO "Setting node for non-present cpu %d\n", cpu);
+}
+
+void __cpuinit numa_clear_node(int cpu)
+{
+       numa_set_node(cpu, NUMA_NO_NODE);
+}
+
+#ifndef CONFIG_DEBUG_PER_CPU_MAPS
+
+void __cpuinit numa_add_cpu(int cpu)
+{
+       cpu_set(cpu, node_to_cpumask_map[early_cpu_to_node(cpu)]);
+}
+
+void __cpuinit numa_remove_cpu(int cpu)
+{
+       cpu_clear(cpu, node_to_cpumask_map[cpu_to_node(cpu)]);
+}
+
+#else /* CONFIG_DEBUG_PER_CPU_MAPS */
+
+/*
+ * --------- debug versions of the numa functions ---------
+ */
+static void __cpuinit numa_set_cpumask(int cpu, int enable)
+{
+       int node = cpu_to_node(cpu);
+       cpumask_t *mask;
+       char buf[64];
+
+       if (node_to_cpumask_map == NULL) {
+               printk(KERN_ERR "node_to_cpumask_map NULL\n");
+               dump_stack();
+               return;
+       }
+
+       mask = &node_to_cpumask_map[node];
+       if (enable)
+               cpu_set(cpu, *mask);
+       else
+               cpu_clear(cpu, *mask);
+
+       cpulist_scnprintf(buf, sizeof(buf), *mask);
+       printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n",
+               enable? "numa_add_cpu":"numa_remove_cpu", cpu, node, buf);
+ }
+
+void __cpuinit numa_add_cpu(int cpu)
+{
+       numa_set_cpumask(cpu, 1);
+}
+
+void __cpuinit numa_remove_cpu(int cpu)
+{
+       numa_set_cpumask(cpu, 0);
+}
+
+int cpu_to_node(int cpu)
+{
+       if (early_per_cpu_ptr(x86_cpu_to_node_map)) {
+               printk(KERN_WARNING
+                       "cpu_to_node(%d): usage too early!\n", cpu);
+               dump_stack();
+               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
+       }
+       return per_cpu(x86_cpu_to_node_map, cpu);
+}
+EXPORT_SYMBOL(cpu_to_node);
+
+/*
+ * Same function as cpu_to_node() but used if called before the
+ * per_cpu areas are setup.
+ */
+int early_cpu_to_node(int cpu)
+{
+       if (early_per_cpu_ptr(x86_cpu_to_node_map))
+               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
+
+       if (!per_cpu_offset(cpu)) {
+               printk(KERN_WARNING
+                       "early_cpu_to_node(%d): no per_cpu area!\n", cpu);
+               dump_stack();
+               return NUMA_NO_NODE;
+       }
+       return per_cpu(x86_cpu_to_node_map, cpu);
+}
+
+
+/* empty cpumask */
+static const cpumask_t cpu_mask_none;
+
+/*
+ * Returns a pointer to the bitmask of CPUs on Node 'node'.
+ */
+const cpumask_t *_node_to_cpumask_ptr(int node)
+{
+       if (node_to_cpumask_map == NULL) {
+               printk(KERN_WARNING
+                       "_node_to_cpumask_ptr(%d): no node_to_cpumask_map!\n",
+                       node);
+               dump_stack();
+               return (const cpumask_t *)&cpu_online_map;
+       }
+       if (node >= nr_node_ids) {
+               printk(KERN_WARNING
+                       "_node_to_cpumask_ptr(%d): node > nr_node_ids(%d)\n",
+                       node, nr_node_ids);
+               dump_stack();
+               return &cpu_mask_none;
+       }
+       return &node_to_cpumask_map[node];
+}
+EXPORT_SYMBOL(_node_to_cpumask_ptr);
+
+/*
+ * Returns a bitmask of CPUs on Node 'node'.
+ *
+ * Side note: this function creates the returned cpumask on the stack
+ * so with a high NR_CPUS count, excessive stack space is used.  The
+ * node_to_cpumask_ptr function should be used whenever possible.
+ */
+cpumask_t node_to_cpumask(int node)
+{
+       if (node_to_cpumask_map == NULL) {
+               printk(KERN_WARNING
+                       "node_to_cpumask(%d): no node_to_cpumask_map!\n", node);
+               dump_stack();
+               return cpu_online_map;
+       }
+       if (node >= nr_node_ids) {
+               printk(KERN_WARNING
+                       "node_to_cpumask(%d): node > nr_node_ids(%d)\n",
+                       node, nr_node_ids);
+               dump_stack();
+               return cpu_mask_none;
+       }
+       return node_to_cpumask_map[node];
+}
+EXPORT_SYMBOL(node_to_cpumask);
+
+/*
+ * --------- end of debug versions of the numa functions ---------
+ */
+
+#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
+
+#endif /* X86_64_NUMA */
+
index 3e1cecedde42747261c94053a53191ffa7291107..f35c2d8016ac412c1c0433bf4382829c1d2cef31 100644 (file)
@@ -59,7 +59,6 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>
-#include <asm/nmi.h>
 #include <asm/vmi.h>
 #include <asm/genapic.h>
 #include <linux/mc146818rtc.h>
 #include <mach_wakecpu.h>
 #include <smpboot_hooks.h>
 
-/*
- * FIXME: For x86_64, those are defined in other files. But moving them here,
- * would make the setup areas dependent on smp, which is a loss. When we
- * integrate apic between arches, we can probably do a better job, but
- * right now, they'll stay here -- glommer
- */
-
-/* which logical CPU number maps to which CPU (physical APIC ID) */
-u16 x86_cpu_to_apicid_init[NR_CPUS] __initdata =
-                       { [0 ... NR_CPUS-1] = BAD_APICID };
-void *x86_cpu_to_apicid_early_ptr;
-
-u16 x86_bios_cpu_apicid_init[NR_CPUS] __initdata
-                               = { [0 ... NR_CPUS-1] = BAD_APICID };
-void *x86_bios_cpu_apicid_early_ptr;
-
 #ifdef CONFIG_X86_32
 u8 apicid_2_node[MAX_APICID];
 static int low_mappings;
@@ -198,13 +181,12 @@ static void map_cpu_to_logical_apicid(void)
        map_cpu_to_node(cpu, node);
 }
 
-static void unmap_cpu_to_logical_apicid(int cpu)
+void numa_remove_cpu(int cpu)
 {
        cpu_2_logical_apicid[cpu] = BAD_APICID;
        unmap_cpu_to_node(cpu);
 }
 #else
-#define unmap_cpu_to_logical_apicid(cpu) do {} while (0)
 #define map_cpu_to_logical_apicid()  do {} while (0)
 #endif
 
@@ -346,15 +328,8 @@ static void __cpuinit start_secondary(void *unused)
         * smp_call_function().
         */
        lock_ipi_call_lock();
-#ifdef CONFIG_X86_64
-       spin_lock(&vector_lock);
-
-       /* Setup the per cpu irq handling data structures */
-       __setup_vector_irq(smp_processor_id());
-       /*
-        * Allow the master to continue.
-        */
-       spin_unlock(&vector_lock);
+#ifdef CONFIG_X86_IO_APIC
+       setup_vector_irq(smp_processor_id());
 #endif
        cpu_set(smp_processor_id(), cpu_online_map);
        unlock_ipi_call_lock();
@@ -366,31 +341,8 @@ static void __cpuinit start_secondary(void *unused)
        cpu_idle();
 }
 
-#ifdef CONFIG_X86_32
-/*
- * Everything has been set up for the secondary
- * CPUs - they just need to reload everything
- * from the task structure
- * This function must not return.
- */
-void __devinit initialize_secondary(void)
-{
-       /*
-        * We don't actually need to load the full TSS,
-        * basically just the stack pointer and the ip.
-        */
-
-       asm volatile(
-               "movl %0,%%esp\n\t"
-               "jmp *%1"
-               :
-               :"m" (current->thread.sp), "m" (current->thread.ip));
-}
-#endif
-
 static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
 {
-#ifdef CONFIG_X86_32
        /*
         * Mask B, Pentium, but not Pentium MMX
         */
@@ -440,7 +392,6 @@ static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
 
 valid_k7:
        ;
-#endif
 }
 
 static void __cpuinit smp_checks(void)
@@ -555,23 +506,6 @@ cpumask_t cpu_coregroup_map(int cpu)
                return c->llc_shared_map;
 }
 
-#ifdef CONFIG_X86_32
-/*
- * We are called very early to get the low memory for the
- * SMP bootup trampoline page.
- */
-void __init smp_alloc_memory(void)
-{
-       trampoline_base = alloc_bootmem_low_pages(PAGE_SIZE);
-       /*
-        * Has to be in very low memory so we can execute
-        * real-mode AP code.
-        */
-       if (__pa(trampoline_base) >= 0x9F000)
-               BUG();
-}
-#endif
-
 static void impress_friends(void)
 {
        int cpu;
@@ -748,11 +682,7 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
         * target processor state.
         */
        startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
-#ifdef CONFIG_X86_64
-                        (unsigned long)init_rsp);
-#else
                         (unsigned long)stack_start.sp);
-#endif
 
        /*
         * Run STARTUP IPI loop.
@@ -832,6 +762,45 @@ static void __cpuinit do_fork_idle(struct work_struct *work)
        complete(&c_idle->done);
 }
 
+#ifdef CONFIG_X86_64
+/*
+ * Allocate node local memory for the AP pda.
+ *
+ * Must be called after the _cpu_pda pointer table is initialized.
+ */
+static int __cpuinit get_local_pda(int cpu)
+{
+       struct x8664_pda *oldpda, *newpda;
+       unsigned long size = sizeof(struct x8664_pda);
+       int node = cpu_to_node(cpu);
+
+       if (cpu_pda(cpu) && !cpu_pda(cpu)->in_bootmem)
+               return 0;
+
+       oldpda = cpu_pda(cpu);
+       newpda = kmalloc_node(size, GFP_ATOMIC, node);
+       if (!newpda) {
+               printk(KERN_ERR "Could not allocate node local PDA "
+                       "for CPU %d on node %d\n", cpu, node);
+
+               if (oldpda)
+                       return 0;       /* have a usable pda */
+               else
+                       return -1;
+       }
+
+       if (oldpda) {
+               memcpy(newpda, oldpda, size);
+               if (!after_bootmem)
+                       free_bootmem((unsigned long)oldpda, size);
+       }
+
+       newpda->in_bootmem = 0;
+       cpu_pda(cpu) = newpda;
+       return 0;
+}
+#endif /* CONFIG_X86_64 */
+
 static int __cpuinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -848,28 +817,14 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
                .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
        };
        INIT_WORK(&c_idle.work, do_fork_idle);
-#ifdef CONFIG_X86_64
-       /* allocate memory for gdts of secondary cpus. Hotplug is considered */
-       if (!cpu_gdt_descr[cpu].address &&
-               !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) {
-               printk(KERN_ERR "Failed to allocate GDT for CPU %d\n", cpu);
-               return -1;
-       }
 
+#ifdef CONFIG_X86_64
        /* Allocate node local memory for AP pdas */
-       if (cpu_pda(cpu) == &boot_cpu_pda[cpu]) {
-               struct x8664_pda *newpda, *pda;
-               int node = cpu_to_node(cpu);
-               pda = cpu_pda(cpu);
-               newpda = kmalloc_node(sizeof(struct x8664_pda), GFP_ATOMIC,
-                                     node);
-               if (newpda) {
-                       memcpy(newpda, pda, sizeof(struct x8664_pda));
-                       cpu_pda(cpu) = newpda;
-               } else
-                       printk(KERN_ERR
-               "Could not allocate node local PDA for CPU %d on node %d\n",
-                               cpu, node);
+       if (cpu > 0) {
+               boot_error = get_local_pda(cpu);
+               if (boot_error)
+                       goto restore_state;
+                       /* if can't get pda memory, can't start cpu */
        }
 #endif
 
@@ -905,18 +860,15 @@ do_rest:
 #ifdef CONFIG_X86_32
        per_cpu(current_task, cpu) = c_idle.idle;
        init_gdt(cpu);
-       early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
-       c_idle.idle->thread.ip = (unsigned long) start_secondary;
        /* Stack for startup_32 can be just as for start_secondary onwards */
-       stack_start.sp = (void *) c_idle.idle->thread.sp;
        irq_ctx_init(cpu);
 #else
        cpu_pda(cpu)->pcurrent = c_idle.idle;
-       init_rsp = c_idle.idle->thread.sp;
-       load_sp0(&per_cpu(init_tss, cpu), &c_idle.idle->thread);
-       initial_code = (unsigned long)start_secondary;
        clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
 #endif
+       early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
+       initial_code = (unsigned long)start_secondary;
+       stack_start.sp = (void *) c_idle.idle->thread.sp;
 
        /* start_ip had better be page-aligned! */
        start_ip = setup_trampoline();
@@ -987,13 +939,12 @@ do_rest:
                                inquire_remote_apic(apicid);
                }
        }
-
-       if (boot_error) {
-               /* Try to put things back the way they were before ... */
-               unmap_cpu_to_logical_apicid(cpu);
 #ifdef CONFIG_X86_64
-               clear_node_cpumask(cpu); /* was set by numa_add_cpu */
+restore_state:
 #endif
+       if (boot_error) {
+               /* Try to put things back the way they were before ... */
+               numa_remove_cpu(cpu); /* was set by numa_add_cpu */
                cpu_clear(cpu, cpu_callout_map); /* was set by do_boot_cpu() */
                cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
                cpu_clear(cpu, cpu_present_map);
@@ -1087,14 +1038,12 @@ static __init void disable_smp(void)
 {
        cpu_present_map = cpumask_of_cpu(0);
        cpu_possible_map = cpumask_of_cpu(0);
-#ifdef CONFIG_X86_32
        smpboot_clear_io_apic_irqs();
-#endif
+
        if (smp_found_config)
-               phys_cpu_present_map =
-                               physid_mask_of_physid(boot_cpu_physical_apicid);
+               physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
        else
-               phys_cpu_present_map = physid_mask_of_physid(0);
+               physid_set_mask_of_physid(0, &phys_cpu_present_map);
        map_cpu_to_logical_apicid();
        cpu_set(0, per_cpu(cpu_sibling_map, 0));
        cpu_set(0, per_cpu(cpu_core_map, 0));
@@ -1157,12 +1106,12 @@ static int __init smp_sanity_check(unsigned max_cpus)
         * If SMP should be disabled, then really disable it!
         */
        if (!max_cpus) {
-               printk(KERN_INFO "SMP mode deactivated,"
-                                "forcing use of dummy APIC emulation.\n");
+               printk(KERN_INFO "SMP mode deactivated.\n");
                smpboot_clear_io_apic();
-#ifdef CONFIG_X86_32
+
+               localise_nmi_watchdog();
+
                connect_bsp_APIC();
-#endif
                setup_local_APIC();
                end_local_APIC_setup();
                return -1;
@@ -1190,7 +1139,6 @@ static void __init smp_cpu_index_default(void)
 void __init native_smp_prepare_cpus(unsigned int max_cpus)
 {
        preempt_disable();
-       nmi_watchdog_default();
        smp_cpu_index_default();
        current_cpu_data = boot_cpu_data;
        cpu_callin_map = cpumask_of_cpu(0);
@@ -1217,9 +1165,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        }
        preempt_enable();
 
-#ifdef CONFIG_X86_32
        connect_bsp_APIC();
-#endif
+
        /*
         * Switch from PIC to APIC mode.
         */
@@ -1257,8 +1204,8 @@ void __init native_smp_prepare_boot_cpu(void)
        int me = smp_processor_id();
 #ifdef CONFIG_X86_32
        init_gdt(me);
-       switch_to_new_gdt();
 #endif
+       switch_to_new_gdt();
        /* already set me in cpu_online_map in boot_cpu_init() */
        cpu_set(me, cpu_callout_map);
        per_cpu(cpu_state, me) = CPU_ONLINE;
@@ -1278,23 +1225,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
 
 #ifdef CONFIG_HOTPLUG_CPU
 
-#  ifdef CONFIG_X86_32
-void cpu_exit_clear(void)
-{
-       int cpu = raw_smp_processor_id();
-
-       idle_task_exit();
-
-       cpu_uninit();
-       irq_ctx_exit(cpu);
-
-       cpu_clear(cpu, cpu_callout_map);
-       cpu_clear(cpu, cpu_callin_map);
-
-       unmap_cpu_to_logical_apicid(cpu);
-}
-#  endif /* CONFIG_X86_32 */
-
 static void remove_siblinginfo(int cpu)
 {
        int sibling;
@@ -1348,12 +1278,20 @@ __init void prefill_possible_map(void)
        int i;
        int possible;
 
+       /* no processor from mptable or madt */
+       if (!num_processors)
+               num_processors = 1;
+
+#ifdef CONFIG_HOTPLUG_CPU
        if (additional_cpus == -1) {
                if (disabled_cpus > 0)
                        additional_cpus = disabled_cpus;
                else
                        additional_cpus = 0;
        }
+#else
+       additional_cpus = 0;
+#endif
        possible = num_processors + additional_cpus;
        if (possible > NR_CPUS)
                possible = NR_CPUS;
@@ -1363,18 +1301,18 @@ __init void prefill_possible_map(void)
 
        for (i = 0; i < possible; i++)
                cpu_set(i, cpu_possible_map);
+
+       nr_cpu_ids = possible;
 }
 
 static void __ref remove_cpu_from_maps(int cpu)
 {
        cpu_clear(cpu, cpu_online_map);
-#ifdef CONFIG_X86_64
        cpu_clear(cpu, cpu_callout_map);
        cpu_clear(cpu, cpu_callin_map);
        /* was set by cpu_init() */
        clear_bit(cpu, (unsigned long *)&cpu_initialized);
-       clear_node_cpumask(cpu);
-#endif
+       numa_remove_cpu(cpu);
 }
 
 int __cpu_disable(void)
index ae751094eba99754b47482aac7bab45d6dd40875..d67ce5f044ba342a327ba634a17ccea09698e040 100644 (file)
@@ -36,7 +36,9 @@ static struct rio_table_hdr *rio_table_hdr __initdata;
 static struct scal_detail   *scal_devs[MAX_NUMNODES] __initdata;
 static struct rio_detail    *rio_devs[MAX_NUMNODES*4] __initdata;
 
+#ifndef CONFIG_X86_NUMAQ
 static int mp_bus_id_to_node[MAX_MP_BUSSES] __initdata;
+#endif
 
 static int __init setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
 {
index d2ab52cc1d6b17fa5ff72ef4e5b6111acc6903f5..7066cb855a60154ea077f855b704bb40c0d58a53 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/utsname.h>
 #include <linux/ipc.h>
 
-#include <asm/uaccess.h>
-#include <asm/unistd.h>
+#include <linux/uaccess.h>
+#include <linux/unistd.h>
 
 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
                          unsigned long prot, unsigned long flags,
@@ -103,7 +103,7 @@ asmlinkage int old_select(struct sel_arg_struct __user *arg)
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc (uint call, int first, int second,
+asmlinkage int sys_ipc(uint call, int first, int second,
                        int third, void __user *ptr, long fifth)
 {
        int version, ret;
@@ -113,24 +113,24 @@ asmlinkage int sys_ipc (uint call, int first, int second,
 
        switch (call) {
        case SEMOP:
-               return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
+               return sys_semtimedop(first, (struct sembuf __user *)ptr, second, NULL);
        case SEMTIMEDOP:
                return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
                                        (const struct timespec __user *)fifth);
 
        case SEMGET:
-               return sys_semget (first, second, third);
+               return sys_semget(first, second, third);
        case SEMCTL: {
                union semun fourth;
                if (!ptr)
                        return -EINVAL;
                if (get_user(fourth.__pad, (void __user * __user *) ptr))
                        return -EFAULT;
-               return sys_semctl (first, second, third, fourth);
+               return sys_semctl(first, second, third, fourth);
        }
 
        case MSGSND:
-               return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
+               return sys_msgsnd(first, (struct msgbuf __user *) ptr,
                                   second, third);
        case MSGRCV:
                switch (version) {
@@ -138,45 +138,45 @@ asmlinkage int sys_ipc (uint call, int first, int second,
                        struct ipc_kludge tmp;
                        if (!ptr)
                                return -EINVAL;
-                       
+
                        if (copy_from_user(&tmp,
-                                          (struct ipc_kludge __user *) ptr, 
-                                          sizeof (tmp)))
+                                          (struct ipc_kludge __user *) ptr,
+                                          sizeof(tmp)))
                                return -EFAULT;
-                       return sys_msgrcv (first, tmp.msgp, second,
+                       return sys_msgrcv(first, tmp.msgp, second,
                                           tmp.msgtyp, third);
                }
                default:
-                       return sys_msgrcv (first,
+                       return sys_msgrcv(first,
                                           (struct msgbuf __user *) ptr,
                                           second, fifth, third);
                }
        case MSGGET:
-               return sys_msgget ((key_t) first, second);
+               return sys_msgget((key_t) first, second);
        case MSGCTL:
-               return sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
+               return sys_msgctl(first, second, (struct msqid_ds __user *) ptr);
 
        case SHMAT:
                switch (version) {
                default: {
                        ulong raddr;
-                       ret = do_shmat (first, (char __user *) ptr, second, &raddr);
+                       ret = do_shmat(first, (char __user *) ptr, second, &raddr);
                        if (ret)
                                return ret;
-                       return put_user (raddr, (ulong __user *) third);
+                       return put_user(raddr, (ulong __user *) third);
                }
                case 1: /* iBCS2 emulator entry point */
                        if (!segment_eq(get_fs(), get_ds()))
                                return -EINVAL;
                        /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
-                       return do_shmat (first, (char __user *) ptr, second, (ulong *) third);
+                       return do_shmat(first, (char __user *) ptr, second, (ulong *) third);
                }
-       case SHMDT: 
-               return sys_shmdt ((char __user *)ptr);
+       case SHMDT:
+               return sys_shmdt((char __user *)ptr);
        case SHMGET:
-               return sys_shmget (first, second, third);
+               return sys_shmget(first, second, third);
        case SHMCTL:
-               return sys_shmctl (first, second,
+               return sys_shmctl(first, second,
                                   (struct shmid_ds __user *) ptr);
        default:
                return -ENOSYS;
@@ -186,28 +186,28 @@ asmlinkage int sys_ipc (uint call, int first, int second,
 /*
  * Old cruft
  */
-asmlinkage int sys_uname(struct old_utsname __user * name)
+asmlinkage int sys_uname(struct old_utsname __user *name)
 {
        int err;
        if (!name)
                return -EFAULT;
        down_read(&uts_sem);
-       err = copy_to_user(name, utsname(), sizeof (*name));
+       err = copy_to_user(name, utsname(), sizeof(*name));
        up_read(&uts_sem);
-       return err?-EFAULT:0;
+       return err? -EFAULT:0;
 }
 
-asmlinkage int sys_olduname(struct oldold_utsname __user * name)
+asmlinkage int sys_olduname(struct oldold_utsname __user *name)
 {
        int error;
 
        if (!name)
                return -EFAULT;
-       if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
                return -EFAULT;
-  
-       down_read(&uts_sem);
-       
+
+       down_read(&uts_sem);
+
        error = __copy_to_user(&name->sysname, &utsname()->sysname,
                               __OLD_UTS_LEN);
        error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
@@ -223,9 +223,9 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name)
        error |= __copy_to_user(&name->machine, &utsname()->machine,
                                __OLD_UTS_LEN);
        error |= __put_user(0, name->machine + __OLD_UTS_LEN);
-       
+
        up_read(&uts_sem);
-       
+
        error = error ? -EFAULT : 0;
 
        return error;
@@ -241,6 +241,6 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
        long __res;
        asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
        : "=a" (__res)
-       : "0" (__NR_execve),"ri" (filename),"c" (argv), "d" (envp) : "memory");
+       : "0" (__NR_execve), "ri" (filename), "c" (argv), "d" (envp) : "memory");
        return __res;
 }
index 2ff21f398934b049975a427e463b046e9226d079..059ca6ee59b4f1bbc9d0eafe4c1f2b3977f17e79 100644 (file)
@@ -39,9 +39,6 @@
 
 #include "do_timer.h"
 
-unsigned int cpu_khz;  /* Detected as we calibrate the TSC */
-EXPORT_SYMBOL(cpu_khz);
-
 int timer_ack;
 
 unsigned long profile_pc(struct pt_regs *regs)
@@ -84,8 +81,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
        if (timer_ack) {
                /*
                 * Subtle, when I/O APICs are used we have to ack timer IRQ
-                * manually to reset the IRR bit for do_slow_gettimeoffset().
-                * This will also deassert NMI lines for the watchdog if run
+                * manually to deassert NMI lines for the watchdog if run
                 * on an 82489DX-based system.
                 */
                spin_lock(&i8259A_lock);
index c737849e2ef7a46b66cce8bc63e230d5a4200da8..e3d49c553af22aec7c773006b7018325dccb6ec0 100644 (file)
@@ -56,7 +56,7 @@ static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
 /* calibrate_cpu is used on systems with fixed rate TSCs to determine
  * processor frequency */
 #define TICK_COUNT 100000000
-unsigned long __init native_calculate_cpu_khz(void)
+unsigned long __init calibrate_cpu(void)
 {
        int tsc_start, tsc_now;
        int i, no_ctr_free;
@@ -116,23 +116,11 @@ void __init hpet_time_init(void)
 
 void __init time_init(void)
 {
-       tsc_calibrate();
-
-       cpu_khz = tsc_khz;
-       if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
-               (boot_cpu_data.x86_vendor == X86_VENDOR_AMD))
-               cpu_khz = calculate_cpu_khz();
-
-       if (unsynchronized_tsc())
-               mark_tsc_unstable("TSCs unsynchronized");
-
+       tsc_init();
        if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
                vgetcpu_mode = VGETCPU_RDTSCP;
        else
                vgetcpu_mode = VGETCPU_LSL;
 
-       printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
-               cpu_khz / 1000, cpu_khz % 1000);
-       init_tsc_clocksource();
        late_time_init = choose_time_init();
 }
index a1f07d7932021bf2beb0dc8d1b644272363c29c9..5039d0f097a2f3cd1a4962418d09a39d5d8eaaff 100644 (file)
@@ -15,6 +15,8 @@
 #include <asm/proto.h>
 #include <asm/apicdef.h>
 #include <asm/idle.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/uv_bau.h>
 
 #include <mach_ipi.h>
 /*
@@ -162,6 +164,9 @@ void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
        union smp_flush_state *f;
        cpumask_t cpumask = *cpumaskp;
 
+       if (is_uv_system() && uv_flush_tlb_others(&cpumask, mm, va))
+               return;
+
        /* Caller has disabled preemption */
        sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS;
        f = &per_cpu(flush_state, sender);
diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c
new file mode 100644 (file)
index 0000000..d0fbb77
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ *     SGI UltraViolet TLB flush routines.
+ *
+ *     (c) 2008 Cliff Wickman <cpw@sgi.com>, SGI.
+ *
+ *     This code is released under the GNU General Public License version 2 or
+ *     later.
+ */
+#include <linux/mc146818rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/kernel.h>
+
+#include <asm/mmu_context.h>
+#include <asm/uv/uv_mmrs.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/uv_bau.h>
+#include <asm/genapic.h>
+#include <asm/idle.h>
+#include <asm/tsc.h>
+
+#include <mach_apic.h>
+
+static struct bau_control      **uv_bau_table_bases __read_mostly;
+static int                     uv_bau_retry_limit __read_mostly;
+
+/* position of pnode (which is nasid>>1): */
+static int                     uv_nshift __read_mostly;
+
+static unsigned long           uv_mmask __read_mostly;
+
+static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
+static DEFINE_PER_CPU(struct bau_control, bau_control);
+
+/*
+ * Free a software acknowledge hardware resource by clearing its Pending
+ * bit. This will return a reply to the sender.
+ * If the message has timed out, a reply has already been sent by the
+ * hardware but the resource has not been released. In that case our
+ * clear of the Timeout bit (as well) will free the resource. No reply will
+ * be sent (the hardware will only do one reply per message).
+ */
+static void uv_reply_to_message(int resource,
+                               struct bau_payload_queue_entry *msg,
+                               struct bau_msg_status *msp)
+{
+       unsigned long dw;
+
+       dw = (1 << (resource + UV_SW_ACK_NPENDING)) | (1 << resource);
+       msg->replied_to = 1;
+       msg->sw_ack_vector = 0;
+       if (msp)
+               msp->seen_by.bits = 0;
+       uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, dw);
+}
+
+/*
+ * Do all the things a cpu should do for a TLB shootdown message.
+ * Other cpu's may come here at the same time for this message.
+ */
+static void uv_bau_process_message(struct bau_payload_queue_entry *msg,
+                                  int msg_slot, int sw_ack_slot)
+{
+       unsigned long this_cpu_mask;
+       struct bau_msg_status *msp;
+       int cpu;
+
+       msp = __get_cpu_var(bau_control).msg_statuses + msg_slot;
+       cpu = uv_blade_processor_id();
+       msg->number_of_cpus =
+           uv_blade_nr_online_cpus(uv_node_to_blade_id(numa_node_id()));
+       this_cpu_mask = 1UL << cpu;
+       if (msp->seen_by.bits & this_cpu_mask)
+               return;
+       atomic_or_long(&msp->seen_by.bits, this_cpu_mask);
+
+       if (msg->replied_to == 1)
+               return;
+
+       if (msg->address == TLB_FLUSH_ALL) {
+               local_flush_tlb();
+               __get_cpu_var(ptcstats).alltlb++;
+       } else {
+               __flush_tlb_one(msg->address);
+               __get_cpu_var(ptcstats).onetlb++;
+       }
+
+       __get_cpu_var(ptcstats).requestee++;
+
+       atomic_inc_short(&msg->acknowledge_count);
+       if (msg->number_of_cpus == msg->acknowledge_count)
+               uv_reply_to_message(sw_ack_slot, msg, msp);
+}
+
+/*
+ * Examine the payload queue on one distribution node to see
+ * which messages have not been seen, and which cpu(s) have not seen them.
+ *
+ * Returns the number of cpu's that have not responded.
+ */
+static int uv_examine_destination(struct bau_control *bau_tablesp, int sender)
+{
+       struct bau_payload_queue_entry *msg;
+       struct bau_msg_status *msp;
+       int count = 0;
+       int i;
+       int j;
+
+       for (msg = bau_tablesp->va_queue_first, i = 0; i < DEST_Q_SIZE;
+            msg++, i++) {
+               if ((msg->sending_cpu == sender) && (!msg->replied_to)) {
+                       msp = bau_tablesp->msg_statuses + i;
+                       printk(KERN_DEBUG
+                              "blade %d: address:%#lx %d of %d, not cpu(s): ",
+                              i, msg->address, msg->acknowledge_count,
+                              msg->number_of_cpus);
+                       for (j = 0; j < msg->number_of_cpus; j++) {
+                               if (!((1L << j) & msp->seen_by.bits)) {
+                                       count++;
+                                       printk("%d ", j);
+                               }
+                       }
+                       printk("\n");
+               }
+       }
+       return count;
+}
+
+/*
+ * Examine the payload queue on all the distribution nodes to see
+ * which messages have not been seen, and which cpu(s) have not seen them.
+ *
+ * Returns the number of cpu's that have not responded.
+ */
+static int uv_examine_destinations(struct bau_target_nodemask *distribution)
+{
+       int sender;
+       int i;
+       int count = 0;
+
+       sender = smp_processor_id();
+       for (i = 0; i < sizeof(struct bau_target_nodemask) * BITSPERBYTE; i++) {
+               if (!bau_node_isset(i, distribution))
+                       continue;
+               count += uv_examine_destination(uv_bau_table_bases[i], sender);
+       }
+       return count;
+}
+
+/*
+ * wait for completion of a broadcast message
+ *
+ * return COMPLETE, RETRY or GIVEUP
+ */
+static int uv_wait_completion(struct bau_desc *bau_desc,
+                             unsigned long mmr_offset, int right_shift)
+{
+       int exams = 0;
+       long destination_timeouts = 0;
+       long source_timeouts = 0;
+       unsigned long descriptor_status;
+
+       while ((descriptor_status = (((unsigned long)
+               uv_read_local_mmr(mmr_offset) >>
+                       right_shift) & UV_ACT_STATUS_MASK)) !=
+                       DESC_STATUS_IDLE) {
+               if (descriptor_status == DESC_STATUS_SOURCE_TIMEOUT) {
+                       source_timeouts++;
+                       if (source_timeouts > SOURCE_TIMEOUT_LIMIT)
+                               source_timeouts = 0;
+                       __get_cpu_var(ptcstats).s_retry++;
+                       return FLUSH_RETRY;
+               }
+               /*
+                * spin here looking for progress at the destinations
+                */
+               if (descriptor_status == DESC_STATUS_DESTINATION_TIMEOUT) {
+                       destination_timeouts++;
+                       if (destination_timeouts > DESTINATION_TIMEOUT_LIMIT) {
+                               /*
+                                * returns number of cpus not responding
+                                */
+                               if (uv_examine_destinations
+                                   (&bau_desc->distribution) == 0) {
+                                       __get_cpu_var(ptcstats).d_retry++;
+                                       return FLUSH_RETRY;
+                               }
+                               exams++;
+                               if (exams >= uv_bau_retry_limit) {
+                                       printk(KERN_DEBUG
+                                              "uv_flush_tlb_others");
+                                       printk("giving up on cpu %d\n",
+                                              smp_processor_id());
+                                       return FLUSH_GIVEUP;
+                               }
+                               /*
+                                * delays can hang the simulator
+                                  udelay(1000);
+                                */
+                               destination_timeouts = 0;
+                       }
+               }
+       }
+       return FLUSH_COMPLETE;
+}
+
+/**
+ * uv_flush_send_and_wait
+ *
+ * Send a broadcast and wait for a broadcast message to complete.
+ *
+ * The cpumaskp mask contains the cpus the broadcast was sent to.
+ *
+ * Returns 1 if all remote flushing was done. The mask is zeroed.
+ * Returns 0 if some remote flushing remains to be done. The mask is left
+ * unchanged.
+ */
+int uv_flush_send_and_wait(int cpu, int this_blade, struct bau_desc *bau_desc,
+                          cpumask_t *cpumaskp)
+{
+       int completion_status = 0;
+       int right_shift;
+       int tries = 0;
+       int blade;
+       int bit;
+       unsigned long mmr_offset;
+       unsigned long index;
+       cycles_t time1;
+       cycles_t time2;
+
+       if (cpu < UV_CPUS_PER_ACT_STATUS) {
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
+               right_shift = cpu * UV_ACT_STATUS_SIZE;
+       } else {
+               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
+               right_shift =
+                   ((cpu - UV_CPUS_PER_ACT_STATUS) * UV_ACT_STATUS_SIZE);
+       }
+       time1 = get_cycles();
+       do {
+               tries++;
+               index = (1UL << UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT) |
+                       cpu;
+               uv_write_local_mmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
+               completion_status = uv_wait_completion(bau_desc, mmr_offset,
+                                       right_shift);
+       } while (completion_status == FLUSH_RETRY);
+       time2 = get_cycles();
+       __get_cpu_var(ptcstats).sflush += (time2 - time1);
+       if (tries > 1)
+               __get_cpu_var(ptcstats).retriesok++;
+
+       if (completion_status == FLUSH_GIVEUP) {
+               /*
+                * Cause the caller to do an IPI-style TLB shootdown on
+                * the cpu's, all of which are still in the mask.
+                */
+               __get_cpu_var(ptcstats).ptc_i++;
+               return 0;
+       }
+
+       /*
+        * Success, so clear the remote cpu's from the mask so we don't
+        * use the IPI method of shootdown on them.
+        */
+       for_each_cpu_mask(bit, *cpumaskp) {
+               blade = uv_cpu_to_blade_id(bit);
+               if (blade == this_blade)
+                       continue;
+               cpu_clear(bit, *cpumaskp);
+       }
+       if (!cpus_empty(*cpumaskp))
+               return 0;
+       return 1;
+}
+
+/**
+ * uv_flush_tlb_others - globally purge translation cache of a virtual
+ * address or all TLB's
+ * @cpumaskp: mask of all cpu's in which the address is to be removed
+ * @mm: mm_struct containing virtual address range
+ * @va: virtual address to be removed (or TLB_FLUSH_ALL for all TLB's on cpu)
+ *
+ * This is the entry point for initiating any UV global TLB shootdown.
+ *
+ * Purges the translation caches of all specified processors of the given
+ * virtual address, or purges all TLB's on specified processors.
+ *
+ * The caller has derived the cpumaskp from the mm_struct and has subtracted
+ * the local cpu from the mask.  This function is called only if there
+ * are bits set in the mask. (e.g. flush_tlb_page())
+ *
+ * The cpumaskp is converted into a nodemask of the nodes containing
+ * the cpus.
+ *
+ * Returns 1 if all remote flushing was done.
+ * Returns 0 if some remote flushing remains to be done.
+ */
+int uv_flush_tlb_others(cpumask_t *cpumaskp, struct mm_struct *mm,
+                       unsigned long va)
+{
+       int i;
+       int bit;
+       int blade;
+       int cpu;
+       int this_blade;
+       int locals = 0;
+       struct bau_desc *bau_desc;
+
+       cpu = uv_blade_processor_id();
+       this_blade = uv_numa_blade_id();
+       bau_desc = __get_cpu_var(bau_control).descriptor_base;
+       bau_desc += UV_ITEMS_PER_DESCRIPTOR * cpu;
+
+       bau_nodes_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
+
+       i = 0;
+       for_each_cpu_mask(bit, *cpumaskp) {
+               blade = uv_cpu_to_blade_id(bit);
+               BUG_ON(blade > (UV_DISTRIBUTION_SIZE - 1));
+               if (blade == this_blade) {
+                       locals++;
+                       continue;
+               }
+               bau_node_set(blade, &bau_desc->distribution);
+               i++;
+       }
+       if (i == 0) {
+               /*
+                * no off_node flushing; return status for local node
+                */
+               if (locals)
+                       return 0;
+               else
+                       return 1;
+       }
+       __get_cpu_var(ptcstats).requestor++;
+       __get_cpu_var(ptcstats).ntargeted += i;
+
+       bau_desc->payload.address = va;
+       bau_desc->payload.sending_cpu = smp_processor_id();
+
+       return uv_flush_send_and_wait(cpu, this_blade, bau_desc, cpumaskp);
+}
+
+/*
+ * The BAU message interrupt comes here. (registered by set_intr_gate)
+ * See entry_64.S
+ *
+ * We received a broadcast assist message.
+ *
+ * Interrupts may have been disabled; this interrupt could represent
+ * the receipt of several messages.
+ *
+ * All cores/threads on this node get this interrupt.
+ * The last one to see it does the s/w ack.
+ * (the resource will not be freed until noninterruptable cpus see this
+ *  interrupt; hardware will timeout the s/w ack and reply ERROR)
+ */
+void uv_bau_message_interrupt(struct pt_regs *regs)
+{
+       struct bau_payload_queue_entry *va_queue_first;
+       struct bau_payload_queue_entry *va_queue_last;
+       struct bau_payload_queue_entry *msg;
+       struct pt_regs *old_regs = set_irq_regs(regs);
+       cycles_t time1;
+       cycles_t time2;
+       int msg_slot;
+       int sw_ack_slot;
+       int fw;
+       int count = 0;
+       unsigned long local_pnode;
+
+       ack_APIC_irq();
+       exit_idle();
+       irq_enter();
+
+       time1 = get_cycles();
+
+       local_pnode = uv_blade_to_pnode(uv_numa_blade_id());
+
+       va_queue_first = __get_cpu_var(bau_control).va_queue_first;
+       va_queue_last = __get_cpu_var(bau_control).va_queue_last;
+
+       msg = __get_cpu_var(bau_control).bau_msg_head;
+       while (msg->sw_ack_vector) {
+               count++;
+               fw = msg->sw_ack_vector;
+               msg_slot = msg - va_queue_first;
+               sw_ack_slot = ffs(fw) - 1;
+
+               uv_bau_process_message(msg, msg_slot, sw_ack_slot);
+
+               msg++;
+               if (msg > va_queue_last)
+                       msg = va_queue_first;
+               __get_cpu_var(bau_control).bau_msg_head = msg;
+       }
+       if (!count)
+               __get_cpu_var(ptcstats).nomsg++;
+       else if (count > 1)
+               __get_cpu_var(ptcstats).multmsg++;
+
+       time2 = get_cycles();
+       __get_cpu_var(ptcstats).dflush += (time2 - time1);
+
+       irq_exit();
+       set_irq_regs(old_regs);
+}
+
+static void uv_enable_timeouts(void)
+{
+       int i;
+       int blade;
+       int last_blade;
+       int pnode;
+       int cur_cpu = 0;
+       unsigned long apicid;
+
+       last_blade = -1;
+       for_each_online_node(i) {
+               blade = uv_node_to_blade_id(i);
+               if (blade == last_blade)
+                       continue;
+               last_blade = blade;
+               apicid = per_cpu(x86_cpu_to_apicid, cur_cpu);
+               pnode = uv_blade_to_pnode(blade);
+               cur_cpu += uv_blade_nr_possible_cpus(i);
+       }
+}
+
+static void *uv_ptc_seq_start(struct seq_file *file, loff_t *offset)
+{
+       if (*offset < num_possible_cpus())
+               return offset;
+       return NULL;
+}
+
+static void *uv_ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
+{
+       (*offset)++;
+       if (*offset < num_possible_cpus())
+               return offset;
+       return NULL;
+}
+
+static void uv_ptc_seq_stop(struct seq_file *file, void *data)
+{
+}
+
+/*
+ * Display the statistics thru /proc
+ * data points to the cpu number
+ */
+static int uv_ptc_seq_show(struct seq_file *file, void *data)
+{
+       struct ptc_stats *stat;
+       int cpu;
+
+       cpu = *(loff_t *)data;
+
+       if (!cpu) {
+               seq_printf(file,
+               "# cpu requestor requestee one all sretry dretry ptc_i ");
+               seq_printf(file,
+               "sw_ack sflush dflush sok dnomsg dmult starget\n");
+       }
+       if (cpu < num_possible_cpus() && cpu_online(cpu)) {
+               stat = &per_cpu(ptcstats, cpu);
+               seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld ",
+                          cpu, stat->requestor,
+                          stat->requestee, stat->onetlb, stat->alltlb,
+                          stat->s_retry, stat->d_retry, stat->ptc_i);
+               seq_printf(file, "%lx %ld %ld %ld %ld %ld %ld\n",
+                          uv_read_global_mmr64(uv_blade_to_pnode
+                                       (uv_cpu_to_blade_id(cpu)),
+                                       UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE),
+                          stat->sflush, stat->dflush,
+                          stat->retriesok, stat->nomsg,
+                          stat->multmsg, stat->ntargeted);
+       }
+
+       return 0;
+}
+
+/*
+ *  0: display meaning of the statistics
+ * >0: retry limit
+ */
+static ssize_t uv_ptc_proc_write(struct file *file, const char __user *user,
+                                size_t count, loff_t *data)
+{
+       long newmode;
+       char optstr[64];
+
+       if (count == 0 || count > sizeof(optstr))
+               return -EINVAL;
+       if (copy_from_user(optstr, user, count))
+               return -EFAULT;
+       optstr[count - 1] = '\0';
+       if (strict_strtoul(optstr, 10, &newmode) < 0) {
+               printk(KERN_DEBUG "%s is invalid\n", optstr);
+               return -EINVAL;
+       }
+
+       if (newmode == 0) {
+               printk(KERN_DEBUG "# cpu:      cpu number\n");
+               printk(KERN_DEBUG
+               "requestor:  times this cpu was the flush requestor\n");
+               printk(KERN_DEBUG
+               "requestee:  times this cpu was requested to flush its TLBs\n");
+               printk(KERN_DEBUG
+               "one:        times requested to flush a single address\n");
+               printk(KERN_DEBUG
+               "all:        times requested to flush all TLB's\n");
+               printk(KERN_DEBUG
+               "sretry:     number of retries of source-side timeouts\n");
+               printk(KERN_DEBUG
+               "dretry:     number of retries of destination-side timeouts\n");
+               printk(KERN_DEBUG
+               "ptc_i:      times UV fell through to IPI-style flushes\n");
+               printk(KERN_DEBUG
+               "sw_ack:     image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE\n");
+               printk(KERN_DEBUG
+               "sflush_us:  cycles spent in uv_flush_tlb_others()\n");
+               printk(KERN_DEBUG
+               "dflush_us:  cycles spent in handling flush requests\n");
+               printk(KERN_DEBUG "sok:        successes on retry\n");
+               printk(KERN_DEBUG "dnomsg:     interrupts with no message\n");
+               printk(KERN_DEBUG
+               "dmult:      interrupts with multiple messages\n");
+               printk(KERN_DEBUG "starget:    nodes targeted\n");
+       } else {
+               uv_bau_retry_limit = newmode;
+               printk(KERN_DEBUG "timeout retry limit:%d\n",
+                      uv_bau_retry_limit);
+       }
+
+       return count;
+}
+
+static const struct seq_operations uv_ptc_seq_ops = {
+       .start          = uv_ptc_seq_start,
+       .next           = uv_ptc_seq_next,
+       .stop           = uv_ptc_seq_stop,
+       .show           = uv_ptc_seq_show
+};
+
+static int uv_ptc_proc_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &uv_ptc_seq_ops);
+}
+
+static const struct file_operations proc_uv_ptc_operations = {
+       .open           = uv_ptc_proc_open,
+       .read           = seq_read,
+       .write          = uv_ptc_proc_write,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __init uv_ptc_init(void)
+{
+       struct proc_dir_entry *proc_uv_ptc;
+
+       if (!is_uv_system())
+               return 0;
+
+       if (!proc_mkdir("sgi_uv", NULL))
+               return -EINVAL;
+
+       proc_uv_ptc = create_proc_entry(UV_PTC_BASENAME, 0444, NULL);
+       if (!proc_uv_ptc) {
+               printk(KERN_ERR "unable to create %s proc entry\n",
+                      UV_PTC_BASENAME);
+               remove_proc_entry("sgi_uv", NULL);
+               return -EINVAL;
+       }
+       proc_uv_ptc->proc_fops = &proc_uv_ptc_operations;
+       return 0;
+}
+
+/*
+ * begin the initialization of the per-blade control structures
+ */
+static struct bau_control * __init uv_table_bases_init(int blade, int node)
+{
+       int i;
+       int *ip;
+       struct bau_msg_status *msp;
+       struct bau_control *bau_tabp;
+
+       bau_tabp =
+           kmalloc_node(sizeof(struct bau_control), GFP_KERNEL, node);
+       BUG_ON(!bau_tabp);
+
+       bau_tabp->msg_statuses =
+           kmalloc_node(sizeof(struct bau_msg_status) *
+                        DEST_Q_SIZE, GFP_KERNEL, node);
+       BUG_ON(!bau_tabp->msg_statuses);
+
+       for (i = 0, msp = bau_tabp->msg_statuses; i < DEST_Q_SIZE; i++, msp++)
+               bau_cpubits_clear(&msp->seen_by, (int)
+                                 uv_blade_nr_possible_cpus(blade));
+
+       bau_tabp->watching =
+           kmalloc_node(sizeof(int) * DEST_NUM_RESOURCES, GFP_KERNEL, node);
+       BUG_ON(!bau_tabp->watching);
+
+       for (i = 0, ip = bau_tabp->watching; i < DEST_Q_SIZE; i++, ip++)
+               *ip = 0;
+
+       uv_bau_table_bases[blade] = bau_tabp;
+
+       return bau_tabp;
+}
+
+/*
+ * finish the initialization of the per-blade control structures
+ */
+static void __init
+uv_table_bases_finish(int blade, int node, int cur_cpu,
+                     struct bau_control *bau_tablesp,
+                     struct bau_desc *adp)
+{
+       struct bau_control *bcp;
+       int i;
+
+       for (i = cur_cpu; i < cur_cpu + uv_blade_nr_possible_cpus(blade); i++) {
+               bcp = (struct bau_control *)&per_cpu(bau_control, i);
+
+               bcp->bau_msg_head       = bau_tablesp->va_queue_first;
+               bcp->va_queue_first     = bau_tablesp->va_queue_first;
+               bcp->va_queue_last      = bau_tablesp->va_queue_last;
+               bcp->watching           = bau_tablesp->watching;
+               bcp->msg_statuses       = bau_tablesp->msg_statuses;
+               bcp->descriptor_base    = adp;
+       }
+}
+
+/*
+ * initialize the sending side's sending buffers
+ */
+static struct bau_desc * __init
+uv_activation_descriptor_init(int node, int pnode)
+{
+       int i;
+       unsigned long pa;
+       unsigned long m;
+       unsigned long n;
+       unsigned long mmr_image;
+       struct bau_desc *adp;
+       struct bau_desc *ad2;
+
+       adp = (struct bau_desc *)
+           kmalloc_node(16384, GFP_KERNEL, node);
+       BUG_ON(!adp);
+
+       pa = __pa((unsigned long)adp);
+       n = pa >> uv_nshift;
+       m = pa & uv_mmask;
+
+       mmr_image = uv_read_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE);
+       if (mmr_image) {
+               uv_write_global_mmr64(pnode, (unsigned long)
+                                     UVH_LB_BAU_SB_DESCRIPTOR_BASE,
+                                     (n << UV_DESC_BASE_PNODE_SHIFT | m));
+       }
+
+       for (i = 0, ad2 = adp; i < UV_ACTIVATION_DESCRIPTOR_SIZE; i++, ad2++) {
+               memset(ad2, 0, sizeof(struct bau_desc));
+               ad2->header.sw_ack_flag = 1;
+               ad2->header.base_dest_nodeid =
+                   uv_blade_to_pnode(uv_cpu_to_blade_id(0));
+               ad2->header.command = UV_NET_ENDPOINT_INTD;
+               ad2->header.int_both = 1;
+               /*
+                * all others need to be set to zero:
+                *   fairness chaining multilevel count replied_to
+                */
+       }
+       return adp;
+}
+
+/*
+ * initialize the destination side's receiving buffers
+ */
+static struct bau_payload_queue_entry * __init
+uv_payload_queue_init(int node, int pnode, struct bau_control *bau_tablesp)
+{
+       struct bau_payload_queue_entry *pqp;
+       char *cp;
+
+       pqp = (struct bau_payload_queue_entry *) kmalloc_node(
+               (DEST_Q_SIZE + 1) * sizeof(struct bau_payload_queue_entry),
+               GFP_KERNEL, node);
+       BUG_ON(!pqp);
+
+       cp = (char *)pqp + 31;
+       pqp = (struct bau_payload_queue_entry *)(((unsigned long)cp >> 5) << 5);
+       bau_tablesp->va_queue_first = pqp;
+       uv_write_global_mmr64(pnode,
+                             UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST,
+                             ((unsigned long)pnode <<
+                              UV_PAYLOADQ_PNODE_SHIFT) |
+                             uv_physnodeaddr(pqp));
+       uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL,
+                             uv_physnodeaddr(pqp));
+       bau_tablesp->va_queue_last = pqp + (DEST_Q_SIZE - 1);
+       uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST,
+                             (unsigned long)
+                             uv_physnodeaddr(bau_tablesp->va_queue_last));
+       memset(pqp, 0, sizeof(struct bau_payload_queue_entry) * DEST_Q_SIZE);
+
+       return pqp;
+}
+
+/*
+ * Initialization of each UV blade's structures
+ */
+static int __init uv_init_blade(int blade, int node, int cur_cpu)
+{
+       int pnode;
+       unsigned long pa;
+       unsigned long apicid;
+       struct bau_desc *adp;
+       struct bau_payload_queue_entry *pqp;
+       struct bau_control *bau_tablesp;
+
+       bau_tablesp = uv_table_bases_init(blade, node);
+       pnode = uv_blade_to_pnode(blade);
+       adp = uv_activation_descriptor_init(node, pnode);
+       pqp = uv_payload_queue_init(node, pnode, bau_tablesp);
+       uv_table_bases_finish(blade, node, cur_cpu, bau_tablesp, adp);
+       /*
+        * the below initialization can't be in firmware because the
+        * messaging IRQ will be determined by the OS
+        */
+       apicid = per_cpu(x86_cpu_to_apicid, cur_cpu);
+       pa = uv_read_global_mmr64(pnode, UVH_BAU_DATA_CONFIG);
+       if ((pa & 0xff) != UV_BAU_MESSAGE) {
+               uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
+                                     ((apicid << 32) | UV_BAU_MESSAGE));
+       }
+       return 0;
+}
+
+/*
+ * Initialization of BAU-related structures
+ */
+static int __init uv_bau_init(void)
+{
+       int blade;
+       int node;
+       int nblades;
+       int last_blade;
+       int cur_cpu = 0;
+
+       if (!is_uv_system())
+               return 0;
+
+       uv_bau_retry_limit = 1;
+       uv_nshift = uv_hub_info->n_val;
+       uv_mmask = (1UL << uv_hub_info->n_val) - 1;
+       nblades = 0;
+       last_blade = -1;
+       for_each_online_node(node) {
+               blade = uv_node_to_blade_id(node);
+               if (blade == last_blade)
+                       continue;
+               last_blade = blade;
+               nblades++;
+       }
+       uv_bau_table_bases = (struct bau_control **)
+           kmalloc(nblades * sizeof(struct bau_control *), GFP_KERNEL);
+       BUG_ON(!uv_bau_table_bases);
+
+       last_blade = -1;
+       for_each_online_node(node) {
+               blade = uv_node_to_blade_id(node);
+               if (blade == last_blade)
+                       continue;
+               last_blade = blade;
+               uv_init_blade(blade, node, cur_cpu);
+               cur_cpu += uv_blade_nr_possible_cpus(blade);
+       }
+       set_intr_gate(UV_BAU_MESSAGE, uv_bau_message_intr1);
+       uv_enable_timeouts();
+
+       return 0;
+}
+__initcall(uv_bau_init);
+__initcall(uv_ptc_init);
index abbf199adebbccda8bb7e51523da6d161e8aa48a..1106fac6024d412fae02df4780464ecd2f9abf4b 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <asm/trampoline.h>
 
-/* ready for x86_64, no harm for x86, since it will overwrite after alloc */
+/* ready for x86_64 and x86 */
 unsigned char *trampoline_base = __va(TRAMPOLINE_BASE);
 
 /*
index 08d752de4eee307779ba20b31c3b1e7c006daa62..8a768973c4f01bdf4b9317d0b23800a233608db9 100644 (file)
@@ -1,5 +1,6 @@
 /*
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  *
  *  Pentium III FXSR, SSE support
  *     Gareth Hughes <gareth@valinux.com>, May 2000
@@ -60,8 +61,6 @@
 
 #include "mach_traps.h"
 
-int panic_on_unrecovered_nmi;
-
 DECLARE_BITMAP(used_vectors, NR_VECTORS);
 EXPORT_SYMBOL_GPL(used_vectors);
 
@@ -98,19 +97,22 @@ asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
+int panic_on_unrecovered_nmi;
 int kstack_depth_to_print = 24;
 static unsigned int code_bytes = 64;
+static int ignore_nmis;
+static int die_counter;
 
 void printk_address(unsigned long address, int reliable)
 {
 #ifdef CONFIG_KALLSYMS
-       char namebuf[KSYM_NAME_LEN];
        unsigned long offset = 0;
        unsigned long symsize;
        const char *symname;
-       char reliab[4] = "";
-       char *delim = ":";
        char *modname;
+       char *delim = ":";
+       char namebuf[KSYM_NAME_LEN];
+       char reliab[4] = "";
 
        symname = kallsyms_lookup(address, &symsize, &offset,
                                        &modname, namebuf);
@@ -130,22 +132,23 @@ void printk_address(unsigned long address, int reliable)
 #endif
 }
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size)
+static inline int valid_stack_ptr(struct thread_info *tinfo,
+                       void *p, unsigned int size)
 {
-       return  p > (void *)tinfo &&
-               p <= (void *)tinfo + THREAD_SIZE - size;
+       void *t = tinfo;
+       return  p > t && p <= t + THREAD_SIZE - size;
 }
 
 /* The form of the top of the frame on the stack */
 struct stack_frame {
-       struct stack_frame      *next_frame;
-       unsigned long           return_address;
+       struct stack_frame *next_frame;
+       unsigned long return_address;
 };
 
 static inline unsigned long
 print_context_stack(struct thread_info *tinfo,
-                   unsigned long *stack, unsigned long bp,
-                   const struct stacktrace_ops *ops, void *data)
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data)
 {
        struct stack_frame *frame = (struct stack_frame *)bp;
 
@@ -167,8 +170,6 @@ print_context_stack(struct thread_info *tinfo,
        return bp;
 }
 
-#define MSG(msg)               ops->warning(data, msg)
-
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
@@ -178,7 +179,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
 
        if (!stack) {
                unsigned long dummy;
-
                stack = &dummy;
                if (task != current)
                        stack = (unsigned long *)task->thread.sp;
@@ -196,7 +196,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
        }
 #endif
 
-       while (1) {
+       for (;;) {
                struct thread_info *context;
 
                context = (struct thread_info *)
@@ -248,10 +248,10 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
 }
 
 static const struct stacktrace_ops print_trace_ops = {
-       .warning                = print_trace_warning,
-       .warning_symbol         = print_trace_warning_symbol,
-       .stack                  = print_trace_stack,
-       .address                = print_trace_address,
+       .warning = print_trace_warning,
+       .warning_symbol = print_trace_warning_symbol,
+       .stack = print_trace_stack,
+       .address = print_trace_address,
 };
 
 static void
@@ -351,15 +351,14 @@ void show_registers(struct pt_regs *regs)
                printk(KERN_EMERG "Code: ");
 
                ip = (u8 *)regs->ip - code_prologue;
-               if (ip < (u8 *)PAGE_OFFSET ||
-                       probe_kernel_address(ip, c)) {
+               if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
                        /* try starting at EIP */
                        ip = (u8 *)regs->ip;
                        code_len = code_len - code_prologue + 1;
                }
                for (i = 0; i < code_len; i++, ip++) {
                        if (ip < (u8 *)PAGE_OFFSET ||
-                               probe_kernel_address(ip, c)) {
+                                       probe_kernel_address(ip, c)) {
                                printk(" Bad EIP value.");
                                break;
                        }
@@ -384,8 +383,6 @@ int is_valid_bugaddr(unsigned long ip)
        return ud2 == 0x0b0f;
 }
 
-static int die_counter;
-
 int __kprobes __die(const char *str, struct pt_regs *regs, long err)
 {
        unsigned short ss;
@@ -402,26 +399,22 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
        printk("DEBUG_PAGEALLOC");
 #endif
        printk("\n");
-
        if (notify_die(DIE_OOPS, str, regs, err,
-                       current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) {
-
-               show_registers(regs);
-               /* Executive summary in case the oops scrolled away */
-               sp = (unsigned long) (&regs->sp);
-               savesegment(ss, ss);
-               if (user_mode(regs)) {
-                       sp = regs->sp;
-                       ss = regs->ss & 0xffff;
-               }
-               printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-               print_symbol("%s", regs->ip);
-               printk(" SS:ESP %04x:%08lx\n", ss, sp);
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+               return 1;
 
-               return 0;
+       show_registers(regs);
+       /* Executive summary in case the oops scrolled away */
+       sp = (unsigned long) (&regs->sp);
+       savesegment(ss, ss);
+       if (user_mode(regs)) {
+               sp = regs->sp;
+               ss = regs->ss & 0xffff;
        }
-
-       return 1;
+       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+       print_symbol("%s", regs->ip);
+       printk(" SS:ESP %04x:%08lx\n", ss, sp);
+       return 0;
 }
 
 /*
@@ -546,7 +539,7 @@ void do_##name(struct pt_regs *regs, long error_code)                       \
 {                                                                      \
        trace_hardirqs_fixup();                                         \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 0, regs, error_code, NULL);         \
 }
@@ -562,7 +555,7 @@ void do_##name(struct pt_regs *regs, long error_code)                       \
        info.si_code = sicode;                                          \
        info.si_addr = (void __user *)siaddr;                           \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 0, regs, error_code, &info);        \
 }
@@ -571,7 +564,7 @@ void do_##name(struct pt_regs *regs, long error_code)                       \
 void do_##name(struct pt_regs *regs, long error_code)                  \
 {                                                                      \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 1, regs, error_code, NULL);         \
 }
@@ -586,27 +579,29 @@ void do_##name(struct pt_regs *regs, long error_code)                     \
        info.si_addr = (void __user *)siaddr;                           \
        trace_hardirqs_fixup();                                         \
        if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                               == NOTIFY_STOP)         \
+                                                       == NOTIFY_STOP) \
                return;                                                 \
        do_trap(trapnr, signr, str, 1, regs, error_code, &info);        \
 }
 
-DO_VM86_ERROR_INFO(0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
 #ifndef CONFIG_KPROBES
 DO_VM86_ERROR(3, SIGTRAP, "int3", int3)
 #endif
 DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow)
 DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO(6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
-DO_ERROR(9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0)
+DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
-DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
+DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
+DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
 DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1)
 
-void __kprobes do_general_protection(struct pt_regs *regs, long error_code)
+void __kprobes
+do_general_protection(struct pt_regs *regs, long error_code)
 {
+       struct task_struct *tsk;
        struct thread_struct *thread;
        struct tss_struct *tss;
        int cpu;
@@ -647,23 +642,24 @@ void __kprobes do_general_protection(struct pt_regs *regs, long error_code)
        if (regs->flags & X86_VM_MASK)
                goto gp_in_vm86;
 
+       tsk = current;
        if (!user_mode(regs))
                goto gp_in_kernel;
 
-       current->thread.error_code = error_code;
-       current->thread.trap_no = 13;
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 13;
 
-       if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
-           printk_ratelimit()) {
+       if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                       printk_ratelimit()) {
                printk(KERN_INFO
-                   "%s[%d] general protection ip:%lx sp:%lx error:%lx",
-                   current->comm, task_pid_nr(current),
-                   regs->ip, regs->sp, error_code);
+                       "%s[%d] general protection ip:%lx sp:%lx error:%lx",
+                       tsk->comm, task_pid_nr(tsk),
+                       regs->ip, regs->sp, error_code);
                print_vma_addr(" in ", regs->ip);
                printk("\n");
        }
 
-       force_sig(SIGSEGV, current);
+       force_sig(SIGSEGV, tsk);
        return;
 
 gp_in_vm86:
@@ -672,14 +668,15 @@ gp_in_vm86:
        return;
 
 gp_in_kernel:
-       if (!fixup_exception(regs)) {
-               current->thread.error_code = error_code;
-               current->thread.trap_no = 13;
-               if (notify_die(DIE_GPF, "general protection fault", regs,
+       if (fixup_exception(regs))
+               return;
+
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 13;
+       if (notify_die(DIE_GPF, "general protection fault", regs,
                                error_code, 13, SIGSEGV) == NOTIFY_STOP)
-                       return;
-               die("general protection fault", regs, error_code);
-       }
+               return;
+       die("general protection fault", regs, error_code);
 }
 
 static notrace __kprobes void
@@ -756,9 +753,9 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
 
 static DEFINE_SPINLOCK(nmi_print_lock);
 
-void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
+void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic)
 {
-       if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == NOTIFY_STOP)
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
                return;
 
        spin_lock(&nmi_print_lock);
@@ -767,10 +764,12 @@ void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
        * to get a message out:
        */
        bust_spinlocks(1);
-       printk(KERN_EMERG "%s", msg);
+       printk(KERN_EMERG "%s", str);
        printk(" on CPU%d, ip %08lx, registers:\n",
                smp_processor_id(), regs->ip);
        show_registers(regs);
+       if (do_panic)
+               panic("Non maskable interrupt");
        console_silent();
        spin_unlock(&nmi_print_lock);
        bust_spinlocks(0);
@@ -790,14 +789,17 @@ void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg)
 static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
        unsigned char reason = 0;
+       int cpu;
+
+       cpu = smp_processor_id();
 
-       /* Only the BSP gets external NMIs from the system: */
-       if (!smp_processor_id())
+       /* Only the BSP gets external NMIs from the system. */
+       if (!cpu)
                reason = get_nmi_reason();
 
        if (!(reason & 0xc0)) {
                if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
-                                                       == NOTIFY_STOP)
+                                                               == NOTIFY_STOP)
                        return;
 #ifdef CONFIG_X86_LOCAL_APIC
                /*
@@ -806,7 +808,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
                 */
                if (nmi_watchdog_tick(regs, reason))
                        return;
-               if (!do_nmi_callback(regs, smp_processor_id()))
+               if (!do_nmi_callback(regs, cpu))
                        unknown_nmi_error(reason, regs);
 #else
                unknown_nmi_error(reason, regs);
@@ -816,6 +818,8 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
        }
        if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
                return;
+
+       /* AK: following checks seem to be broken on modern chipsets. FIXME */
        if (reason & 0x80)
                mem_parity_error(reason, regs);
        if (reason & 0x40)
@@ -827,8 +831,6 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
        reassert_nmi();
 }
 
-static int ignore_nmis;
-
 notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code)
 {
        int cpu;
@@ -913,7 +915,7 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
        tsk->thread.debugctlmsr = 0;
 
        if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
-                                       SIGTRAP) == NOTIFY_STOP)
+                                               SIGTRAP) == NOTIFY_STOP)
                return;
        /* It's safe to allow irq's after DR6 has been saved */
        if (regs->flags & X86_EFLAGS_IF)
@@ -974,9 +976,8 @@ clear_TF_reenable:
 void math_error(void __user *ip)
 {
        struct task_struct *task;
-       unsigned short cwd;
-       unsigned short swd;
        siginfo_t info;
+       unsigned short cwd, swd;
 
        /*
         * Save the info for the exception handler and clear the error.
@@ -995,7 +996,7 @@ void math_error(void __user *ip)
         * C1 reg you need in case of a stack fault, 0x040 is the stack
         * fault bit.  We should only be taking one exception at a time,
         * so if this combination doesn't produce any single exception,
-        * then we have a bad program that isn't syncronizing its FPU usage
+        * then we have a bad program that isn't synchronizing its FPU usage
         * and it will suffer the consequences since we won't be able to
         * fully reproduce the context of the exception
         */
@@ -1004,7 +1005,7 @@ void math_error(void __user *ip)
        switch (swd & ~cwd & 0x3f) {
        case 0x000: /* No unmasked exception */
                return;
-       default:    /* Multiple exceptions */
+       default: /* Multiple exceptions */
                break;
        case 0x001: /* Invalid Op */
                /*
@@ -1040,8 +1041,8 @@ void do_coprocessor_error(struct pt_regs *regs, long error_code)
 static void simd_math_error(void __user *ip)
 {
        struct task_struct *task;
-       unsigned short mxcsr;
        siginfo_t info;
+       unsigned short mxcsr;
 
        /*
         * Save the info for the exception handler and clear the error.
@@ -1117,7 +1118,7 @@ void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 
 unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp)
 {
-       struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
+       struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id());
        unsigned long base = (kesp - uesp) & -THREAD_SIZE;
        unsigned long new_kesp = kesp - base;
        unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
@@ -1196,19 +1197,16 @@ void __init trap_init(void)
        early_iounmap(p, 4);
 #endif
 
-#ifdef CONFIG_X86_LOCAL_APIC
-       init_apic_mappings();
-#endif
-       set_trap_gate(0,  &divide_error);
-       set_intr_gate(1,  &debug);
-       set_intr_gate(2,  &nmi);
-       set_system_intr_gate(3, &int3); /* int3/4 can be called from all */
-       set_system_gate(4, &overflow);
-       set_trap_gate(5,  &bounds);
-       set_trap_gate(6,  &invalid_op);
-       set_trap_gate(7,  &device_not_available);
-       set_task_gate(8,  GDT_ENTRY_DOUBLEFAULT_TSS);
-       set_trap_gate(9,  &coprocessor_segment_overrun);
+       set_trap_gate(0, &divide_error);
+       set_intr_gate(1, &debug);
+       set_intr_gate(2, &nmi);
+       set_system_intr_gate(3, &int3); /* int3 can be called from all */
+       set_system_gate(4, &overflow); /* int4 can be called from all */
+       set_trap_gate(5, &bounds);
+       set_trap_gate(6, &invalid_op);
+       set_trap_gate(7, &device_not_available);
+       set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
+       set_trap_gate(9, &coprocessor_segment_overrun);
        set_trap_gate(10, &invalid_TSS);
        set_trap_gate(11, &segment_not_present);
        set_trap_gate(12, &stack_segment);
index adff76ea97c4732de4b7766272c8b6ad26ace478..2696a683778204e2f1b417ab4929f27f657836bf 100644 (file)
  * 'Traps.c' handles hardware traps and faults after we have saved some
  * state in 'entry.S'.
  */
-#include <linux/sched.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
+#include <linux/spinlock.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/kdebug.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
 #include <linux/string.h>
+#include <linux/unwind.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
-#include <linux/ptrace.h>
+#include <linux/kexec.h>
+#include <linux/sched.h>
 #include <linux/timer.h>
-#include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/kallsyms.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/nmi.h>
-#include <linux/kprobes.h>
-#include <linux/kexec.h>
-#include <linux/unwind.h>
-#include <linux/uaccess.h>
 #include <linux/bug.h>
-#include <linux/kdebug.h>
-#include <linux/utsname.h>
-
-#include <mach_traps.h>
+#include <linux/nmi.h>
+#include <linux/mm.h>
 
 #if defined(CONFIG_EDAC)
 #include <linux/edac.h>
 #endif
 
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/atomic.h>
+#include <asm/stacktrace.h>
+#include <asm/processor.h>
 #include <asm/debugreg.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/unwind.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
-#include <asm/processor.h>
-#include <asm/unwind.h>
+#include <asm/nmi.h>
 #include <asm/smp.h>
+#include <asm/io.h>
 #include <asm/pgalloc.h>
-#include <asm/pda.h>
 #include <asm/proto.h>
-#include <asm/nmi.h>
-#include <asm/stacktrace.h>
+#include <asm/pda.h>
+
+#include <mach_traps.h>
 
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
@@ -71,12 +71,15 @@ asmlinkage void general_protection(void);
 asmlinkage void page_fault(void);
 asmlinkage void coprocessor_error(void);
 asmlinkage void simd_coprocessor_error(void);
-asmlinkage void reserved(void);
 asmlinkage void alignment_check(void);
-asmlinkage void machine_check(void);
 asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void machine_check(void);
 
+int panic_on_unrecovered_nmi;
+int kstack_depth_to_print = 12;
 static unsigned int code_bytes = 64;
+static int ignore_nmis;
+static int die_counter;
 
 static inline void conditional_sti(struct pt_regs *regs)
 {
@@ -100,34 +103,9 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
        dec_preempt_count();
 }
 
-int kstack_depth_to_print = 12;
-
 void printk_address(unsigned long address, int reliable)
 {
-#ifdef CONFIG_KALLSYMS
-       unsigned long offset = 0, symsize;
-       const char *symname;
-       char *modname;
-       char *delim = ":";
-       char namebuf[KSYM_NAME_LEN];
-       char reliab[4] = "";
-
-       symname = kallsyms_lookup(address, &symsize, &offset,
-                                       &modname, namebuf);
-       if (!symname) {
-               printk(" [<%016lx>]\n", address);
-               return;
-       }
-       if (!reliable)
-               strcpy(reliab, "? ");
-
-       if (!modname)
-               modname = delim = "";
-       printk(" [<%016lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
-               address, reliab, delim, modname, delim, symname, offset, symsize);
-#else
-       printk(" [<%016lx>]\n", address);
-#endif
+       printk(" [<%016lx>] %s%pS\n", address, reliable ? "": "? ", (void *) address);
 }
 
 static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
@@ -204,8 +182,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
        return NULL;
 }
 
-#define MSG(txt) ops->warning(data, txt)
-
 /*
  * x86-64 can have up to three kernel stacks: 
  * process stack
@@ -232,11 +208,11 @@ struct stack_frame {
        unsigned long return_address;
 };
 
-
-static inline unsigned long print_context_stack(struct thread_info *tinfo,
-                               unsigned long *stack, unsigned long bp,
-                               const struct stacktrace_ops *ops, void *data,
-                               unsigned long *end)
+static inline unsigned long
+print_context_stack(struct thread_info *tinfo,
+               unsigned long *stack, unsigned long bp,
+               const struct stacktrace_ops *ops, void *data,
+               unsigned long *end)
 {
        struct stack_frame *frame = (struct stack_frame *)bp;
 
@@ -258,7 +234,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
        return bp;
 }
 
-void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
                unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
 {
@@ -267,36 +243,34 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
        unsigned used = 0;
        struct thread_info *tinfo;
 
-       if (!tsk)
-               tsk = current;
-       tinfo = task_thread_info(tsk);
+       if (!task)
+               task = current;
 
        if (!stack) {
                unsigned long dummy;
                stack = &dummy;
-               if (tsk && tsk != current)
-                       stack = (unsigned long *)tsk->thread.sp;
+               if (task && task != current)
+                       stack = (unsigned long *)task->thread.sp;
        }
 
 #ifdef CONFIG_FRAME_POINTER
        if (!bp) {
-               if (tsk == current) {
+               if (task == current) {
                        /* Grab bp right from our regs */
-                       asm("movq %%rbp, %0" : "=r" (bp):);
+                       asm("movq %%rbp, %0" : "=r" (bp) :);
                } else {
                        /* bp is the last reg pushed by switch_to */
-                       bp = *(unsigned long *) tsk->thread.sp;
+                       bp = *(unsigned long *) task->thread.sp;
                }
        }
 #endif
 
-
-
        /*
         * Print function call entries in all stacks, starting at the
         * current stack address. If the stacks consist of nested
         * exceptions
         */
+       tinfo = task_thread_info(task);
        for (;;) {
                char *id;
                unsigned long *estack_end;
@@ -381,18 +355,17 @@ static const struct stacktrace_ops print_trace_ops = {
        .address = print_trace_address,
 };
 
-void
-show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack,
-               unsigned long bp)
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *stack, unsigned long bp)
 {
        printk("\nCall Trace:\n");
-       dump_trace(tsk, regs, stack, bp, &print_trace_ops, NULL);
+       dump_trace(task, regs, stack, bp, &print_trace_ops, NULL);
        printk("\n");
 }
 
 static void
-_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp,
-                                                       unsigned long bp)
+_show_stack(struct task_struct *task, struct pt_regs *regs,
+               unsigned long *sp, unsigned long bp)
 {
        unsigned long *stack;
        int i;
@@ -404,14 +377,14 @@ _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp,
        // back trace for this cpu.
 
        if (sp == NULL) {
-               if (tsk)
-                       sp = (unsigned long *)tsk->thread.sp;
+               if (task)
+                       sp = (unsigned long *)task->thread.sp;
                else
                        sp = (unsigned long *)&sp;
        }
 
        stack = sp;
-       for(i=0; i < kstack_depth_to_print; i++) {
+       for (i = 0; i < kstack_depth_to_print; i++) {
                if (stack >= irqstack && stack <= irqstack_end) {
                        if (stack == irqstack_end) {
                                stack = (unsigned long *) (irqstack_end[-1]);
@@ -426,12 +399,12 @@ _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp,
                printk(" %016lx", *stack++);
                touch_nmi_watchdog();
        }
-       show_trace(tsk, regs, sp, bp);
+       show_trace(task, regs, sp, bp);
 }
 
-void show_stack(struct task_struct *tsk, unsigned long * sp)
+void show_stack(struct task_struct *task, unsigned long *sp)
 {
-       _show_stack(tsk, NULL, sp, 0);
+       _show_stack(task, NULL, sp, 0);
 }
 
 /*
@@ -439,8 +412,8 @@ void show_stack(struct task_struct *tsk, unsigned long * sp)
  */
 void dump_stack(void)
 {
-       unsigned long dummy;
        unsigned long bp = 0;
+       unsigned long stack;
 
 #ifdef CONFIG_FRAME_POINTER
        if (!bp)
@@ -452,7 +425,7 @@ void dump_stack(void)
                init_utsname()->release,
                (int)strcspn(init_utsname()->version, " "),
                init_utsname()->version);
-       show_trace(NULL, NULL, &dummy, bp);
+       show_trace(NULL, NULL, &stack, bp);
 }
 
 EXPORT_SYMBOL(dump_stack);
@@ -463,12 +436,8 @@ void show_registers(struct pt_regs *regs)
        unsigned long sp;
        const int cpu = smp_processor_id();
        struct task_struct *cur = cpu_pda(cpu)->pcurrent;
-       u8 *ip;
-       unsigned int code_prologue = code_bytes * 43 / 64;
-       unsigned int code_len = code_bytes;
 
        sp = regs->sp;
-       ip = (u8 *) regs->ip - code_prologue;
        printk("CPU %d ", cpu);
        __show_regs(regs);
        printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
@@ -479,15 +448,21 @@ void show_registers(struct pt_regs *regs)
         * time of the fault..
         */
        if (!user_mode(regs)) {
+               unsigned int code_prologue = code_bytes * 43 / 64;
+               unsigned int code_len = code_bytes;
                unsigned char c;
+               u8 *ip;
+
                printk("Stack: ");
                _show_stack(NULL, regs, (unsigned long *)sp, regs->bp);
                printk("\n");
 
                printk(KERN_EMERG "Code: ");
+
+               ip = (u8 *)regs->ip - code_prologue;
                if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
                        /* try starting at RIP */
-                       ip = (u8 *) regs->ip;
+                       ip = (u8 *)regs->ip;
                        code_len = code_len - code_prologue + 1;
                }
                for (i = 0; i < code_len; i++, ip++) {
@@ -503,7 +478,7 @@ void show_registers(struct pt_regs *regs)
                }
        }
        printk("\n");
-}      
+}
 
 int is_valid_bugaddr(unsigned long ip)
 {
@@ -561,10 +536,9 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
        do_exit(signr);
 }
 
-int __kprobes __die(const char * str, struct pt_regs * regs, long err)
+int __kprobes __die(const char *str, struct pt_regs *regs, long err)
 {
-       static int die_counter;
-       printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
+       printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff, ++die_counter);
 #ifdef CONFIG_PREEMPT
        printk("PREEMPT ");
 #endif
@@ -575,8 +549,10 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err)
        printk("DEBUG_PAGEALLOC");
 #endif
        printk("\n");
-       if (notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
+       if (notify_die(DIE_OOPS, str, regs, err,
+                       current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
                return 1;
+
        show_registers(regs);
        add_taint(TAINT_DIE);
        /* Executive summary in case the oops scrolled away */
@@ -588,7 +564,7 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err)
        return 0;
 }
 
-void die(const char * str, struct pt_regs * regs, long err)
+void die(const char *str, struct pt_regs *regs, long err)
 {
        unsigned long flags = oops_begin();
 
@@ -605,8 +581,7 @@ die_nmi(char *str, struct pt_regs *regs, int do_panic)
 {
        unsigned long flags;
 
-       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) ==
-           NOTIFY_STOP)
+       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
                return;
 
        flags = oops_begin();
@@ -614,7 +589,9 @@ die_nmi(char *str, struct pt_regs *regs, int do_panic)
         * We are in trouble anyway, lets at least try
         * to get a message out.
         */
-       printk(str, smp_processor_id());
+       printk(KERN_EMERG "%s", str);
+       printk(" on CPU%d, ip %08lx, registers:\n",
+               smp_processor_id(), regs->ip);
        show_registers(regs);
        if (kexec_should_crash(current))
                crash_kexec(regs);
@@ -626,44 +603,44 @@ die_nmi(char *str, struct pt_regs *regs, int do_panic)
        do_exit(SIGBUS);
 }
 
-static void __kprobes do_trap(int trapnr, int signr, char *str,
-                             struct pt_regs * regs, long error_code,
-                             siginfo_t *info)
+static void __kprobes
+do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
+       long error_code, siginfo_t *info)
 {
        struct task_struct *tsk = current;
 
-       if (user_mode(regs)) {
-               /*
-                * We want error_code and trap_no set for userspace
-                * faults and kernelspace faults which result in
-                * die(), but not kernelspace faults which are fixed
-                * up.  die() gives the process no chance to handle
-                * the signal and notice the kernel fault information,
-                * so that won't result in polluting the information
-                * about previously queued, but not yet delivered,
-                * faults.  See also do_general_protection below.
-                */
-               tsk->thread.error_code = error_code;
-               tsk->thread.trap_no = trapnr;
-
-               if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
-                   printk_ratelimit()) {
-                       printk(KERN_INFO
-                              "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-                              tsk->comm, tsk->pid, str,
-                              regs->ip, regs->sp, error_code);
-                       print_vma_addr(" in ", regs->ip);
-                       printk("\n");
-               }
+       if (!user_mode(regs))
+               goto kernel_trap;
 
-               if (info)
-                       force_sig_info(signr, info, tsk);
-               else
-                       force_sig(signr, tsk);
-               return;
+       /*
+        * We want error_code and trap_no set for userspace faults and
+        * kernelspace faults which result in die(), but not
+        * kernelspace faults which are fixed up.  die() gives the
+        * process no chance to handle the signal and notice the
+        * kernel fault information, so that won't result in polluting
+        * the information about previously queued, but not yet
+        * delivered, faults.  See also do_general_protection below.
+        */
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = trapnr;
+
+       if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+           printk_ratelimit()) {
+               printk(KERN_INFO
+                      "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+                      tsk->comm, tsk->pid, str,
+                      regs->ip, regs->sp, error_code);
+               print_vma_addr(" in ", regs->ip);
+               printk("\n");
        }
 
+       if (info)
+               force_sig_info(signr, info, tsk);
+       else
+               force_sig(signr, tsk);
+       return;
 
+kernel_trap:
        if (!fixup_exception(regs)) {
                tsk->thread.error_code = error_code;
                tsk->thread.trap_no = trapnr;
@@ -673,41 +650,39 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
 }
 
 #define DO_ERROR(trapnr, signr, str, name) \
-asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
-{ \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
-                                                       == NOTIFY_STOP) \
-               return; \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code)      \
+{                                                                      \
+       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
+                                                       == NOTIFY_STOP) \
+               return;                                                 \
        conditional_sti(regs);                                          \
-       do_trap(trapnr, signr, str, regs, error_code, NULL); \
+       do_trap(trapnr, signr, str, regs, error_code, NULL);            \
 }
 
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
-asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
-{ \
-       siginfo_t info; \
-       info.si_signo = signr; \
-       info.si_errno = 0; \
-       info.si_code = sicode; \
-       info.si_addr = (void __user *)siaddr; \
-       trace_hardirqs_fixup(); \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
-                                                       == NOTIFY_STOP) \
-               return; \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)                \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code)      \
+{                                                                      \
+       siginfo_t info;                                                 \
+       info.si_signo = signr;                                          \
+       info.si_errno = 0;                                              \
+       info.si_code = sicode;                                          \
+       info.si_addr = (void __user *)siaddr;                           \
+       trace_hardirqs_fixup();                                         \
+       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
+                                                       == NOTIFY_STOP) \
+               return;                                                 \
        conditional_sti(regs);                                          \
-       do_trap(trapnr, signr, str, regs, error_code, &info); \
+       do_trap(trapnr, signr, str, regs, error_code, &info);           \
 }
 
-DO_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->ip)
-DO_ERROR( 4, SIGSEGV, "overflow", overflow)
-DO_ERROR( 5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO( 6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
-DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
-DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip)
+DO_ERROR(4, SIGSEGV, "overflow", overflow)
+DO_ERROR(5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip)
+DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
-DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
+DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-DO_ERROR(18, SIGSEGV, "reserved", reserved)
 
 /* Runs on IST stack */
 asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code)
@@ -737,31 +712,34 @@ asmlinkage void do_double_fault(struct pt_regs * regs, long error_code)
                die(str, regs, error_code);
 }
 
-asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
-                                               long error_code)
+asmlinkage void __kprobes
+do_general_protection(struct pt_regs *regs, long error_code)
 {
-       struct task_struct *tsk = current;
+       struct task_struct *tsk;
 
        conditional_sti(regs);
 
-       if (user_mode(regs)) {
-               tsk->thread.error_code = error_code;
-               tsk->thread.trap_no = 13;
-
-               if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
-                   printk_ratelimit()) {
-                       printk(KERN_INFO
-                      "%s[%d] general protection ip:%lx sp:%lx error:%lx",
-                              tsk->comm, tsk->pid,
-                              regs->ip, regs->sp, error_code);
-                       print_vma_addr(" in ", regs->ip);
-                       printk("\n");
-               }
+       tsk = current;
+       if (!user_mode(regs))
+               goto gp_in_kernel;
 
-               force_sig(SIGSEGV, tsk);
-               return;
-       } 
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 13;
+
+       if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+                       printk_ratelimit()) {
+               printk(KERN_INFO
+                       "%s[%d] general protection ip:%lx sp:%lx error:%lx",
+                       tsk->comm, tsk->pid,
+                       regs->ip, regs->sp, error_code);
+               print_vma_addr(" in ", regs->ip);
+               printk("\n");
+       }
 
+       force_sig(SIGSEGV, tsk);
+       return;
+
+gp_in_kernel:
        if (fixup_exception(regs))
                return;
 
@@ -774,14 +752,14 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
 }
 
 static notrace __kprobes void
-mem_parity_error(unsigned char reason, struct pt_regs * regs)
+mem_parity_error(unsigned char reason, struct pt_regs *regs)
 {
        printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
                reason);
        printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
 
 #if defined(CONFIG_EDAC)
-       if(edac_handler_set()) {
+       if (edac_handler_set()) {
                edac_atomic_assert_error();
                return;
        }
@@ -798,7 +776,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
 }
 
 static notrace __kprobes void
-io_check_error(unsigned char reason, struct pt_regs * regs)
+io_check_error(unsigned char reason, struct pt_regs *regs)
 {
        printk("NMI: IOCK error (debug interrupt?)\n");
        show_registers(regs);
@@ -828,14 +806,14 @@ unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
 
 /* Runs on IST stack. This code must keep interrupts off all the time.
    Nested NMIs are prevented by the CPU. */
-asmlinkage notrace  __kprobes void default_do_nmi(struct pt_regs *regs)
+asmlinkage notrace __kprobes void default_do_nmi(struct pt_regs *regs)
 {
        unsigned char reason = 0;
        int cpu;
 
        cpu = smp_processor_id();
 
-       /* Only the BSP gets external NMIs from the system.  */
+       /* Only the BSP gets external NMIs from the system. */
        if (!cpu)
                reason = get_nmi_reason();
 
@@ -847,32 +825,57 @@ asmlinkage notrace  __kprobes void default_do_nmi(struct pt_regs *regs)
                 * Ok, so this is none of the documented NMI sources,
                 * so it must be the NMI watchdog.
                 */
-               if (nmi_watchdog_tick(regs,reason))
+               if (nmi_watchdog_tick(regs, reason))
                        return;
-               if (!do_nmi_callback(regs,cpu))
+               if (!do_nmi_callback(regs, cpu))
                        unknown_nmi_error(reason, regs);
 
                return;
        }
        if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
-               return; 
+               return;
 
        /* AK: following checks seem to be broken on modern chipsets. FIXME */
-
        if (reason & 0x80)
                mem_parity_error(reason, regs);
        if (reason & 0x40)
                io_check_error(reason, regs);
 }
 
+asmlinkage notrace __kprobes void
+do_nmi(struct pt_regs *regs, long error_code)
+{
+       nmi_enter();
+
+       add_pda(__nmi_count, 1);
+
+       if (!ignore_nmis)
+               default_do_nmi(regs);
+
+       nmi_exit();
+}
+
+void stop_nmi(void)
+{
+       acpi_nmi_disable();
+       ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+       ignore_nmis--;
+       acpi_nmi_enable();
+}
+
 /* runs on IST stack. */
-asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
+asmlinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
        trace_hardirqs_fixup();
 
-       if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
+       if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
+                       == NOTIFY_STOP)
                return;
-       }
+
        preempt_conditional_sti(regs);
        do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
        preempt_conditional_cli(regs);
@@ -903,8 +906,8 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
 asmlinkage void __kprobes do_debug(struct pt_regs * regs,
                                   unsigned long error_code)
 {
-       unsigned long condition;
        struct task_struct *tsk = current;
+       unsigned long condition;
        siginfo_t info;
 
        trace_hardirqs_fixup();
@@ -925,21 +928,19 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,
 
        /* Mask out spurious debug traps due to lazy DR7 setting */
        if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-               if (!tsk->thread.debugreg7) { 
+               if (!tsk->thread.debugreg7)
                        goto clear_dr7;
-               }
        }
 
        tsk->thread.debugreg6 = condition;
 
-
        /*
         * Single-stepping through TF: make sure we ignore any events in
         * kernel space (but re-enable TF when returning to user mode).
         */
        if (condition & DR_STEP) {
-                if (!user_mode(regs))
-                       goto clear_TF_reenable;
+               if (!user_mode(regs))
+                       goto clear_TF_reenable;
        }
 
        /* Ok, finally something we can handle */
@@ -952,7 +953,7 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,
        force_sig_info(SIGTRAP, &info, tsk);
 
 clear_dr7:
-       set_debugreg(0UL, 7);
+       set_debugreg(0, 7);
        preempt_conditional_cli(regs);
        return;
 
@@ -960,6 +961,7 @@ clear_TF_reenable:
        set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
        regs->flags &= ~X86_EFLAGS_TF;
        preempt_conditional_cli(regs);
+       return;
 }
 
 static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
@@ -982,7 +984,7 @@ static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr)
 asmlinkage void do_coprocessor_error(struct pt_regs *regs)
 {
        void __user *ip = (void __user *)(regs->ip);
-       struct task_struct * task;
+       struct task_struct *task;
        siginfo_t info;
        unsigned short cwd, swd;
 
@@ -1015,30 +1017,30 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs)
        cwd = get_fpu_cwd(task);
        swd = get_fpu_swd(task);
        switch (swd & ~cwd & 0x3f) {
-               case 0x000:
-               default:
-                       break;
-               case 0x001: /* Invalid Op */
-                       /*
-                        * swd & 0x240 == 0x040: Stack Underflow
-                        * swd & 0x240 == 0x240: Stack Overflow
-                        * User must clear the SF bit (0x40) if set
-                        */
-                       info.si_code = FPE_FLTINV;
-                       break;
-               case 0x002: /* Denormalize */
-               case 0x010: /* Underflow */
-                       info.si_code = FPE_FLTUND;
-                       break;
-               case 0x004: /* Zero Divide */
-                       info.si_code = FPE_FLTDIV;
-                       break;
-               case 0x008: /* Overflow */
-                       info.si_code = FPE_FLTOVF;
-                       break;
-               case 0x020: /* Precision */
-                       info.si_code = FPE_FLTRES;
-                       break;
+       case 0x000: /* No unmasked exception */
+       default: /* Multiple exceptions */
+               break;
+       case 0x001: /* Invalid Op */
+               /*
+                * swd & 0x240 == 0x040: Stack Underflow
+                * swd & 0x240 == 0x240: Stack Overflow
+                * User must clear the SF bit (0x40) if set
+                */
+               info.si_code = FPE_FLTINV;
+               break;
+       case 0x002: /* Denormalize */
+       case 0x010: /* Underflow */
+               info.si_code = FPE_FLTUND;
+               break;
+       case 0x004: /* Zero Divide */
+               info.si_code = FPE_FLTDIV;
+               break;
+       case 0x008: /* Overflow */
+               info.si_code = FPE_FLTOVF;
+               break;
+       case 0x020: /* Precision */
+               info.si_code = FPE_FLTRES;
+               break;
        }
        force_sig_info(SIGFPE, &info, task);
 }
@@ -1051,7 +1053,7 @@ asmlinkage void bad_intr(void)
 asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
 {
        void __user *ip = (void __user *)(regs->ip);
-       struct task_struct * task;
+       struct task_struct *task;
        siginfo_t info;
        unsigned short mxcsr;
 
@@ -1079,25 +1081,25 @@ asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
         */
        mxcsr = get_fpu_mxcsr(task);
        switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
-               case 0x000:
-               default:
-                       break;
-               case 0x001: /* Invalid Op */
-                       info.si_code = FPE_FLTINV;
-                       break;
-               case 0x002: /* Denormalize */
-               case 0x010: /* Underflow */
-                       info.si_code = FPE_FLTUND;
-                       break;
-               case 0x004: /* Zero Divide */
-                       info.si_code = FPE_FLTDIV;
-                       break;
-               case 0x008: /* Overflow */
-                       info.si_code = FPE_FLTOVF;
-                       break;
-               case 0x020: /* Precision */
-                       info.si_code = FPE_FLTRES;
-                       break;
+       case 0x000:
+       default:
+               break;
+       case 0x001: /* Invalid Op */
+               info.si_code = FPE_FLTINV;
+               break;
+       case 0x002: /* Denormalize */
+       case 0x010: /* Underflow */
+               info.si_code = FPE_FLTUND;
+               break;
+       case 0x004: /* Zero Divide */
+               info.si_code = FPE_FLTDIV;
+               break;
+       case 0x008: /* Overflow */
+               info.si_code = FPE_FLTOVF;
+               break;
+       case 0x020: /* Precision */
+               info.si_code = FPE_FLTRES;
+               break;
        }
        force_sig_info(SIGFPE, &info, task);
 }
@@ -1115,7 +1117,7 @@ asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
 }
 
 /*
- *  'math_state_restore()' saves the current math information in the
+ * 'math_state_restore()' saves the current math information in the
  * old math state array, and gets the new ones from the current task
  *
  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
@@ -1140,7 +1142,7 @@ asmlinkage void math_state_restore(void)
                local_irq_disable();
        }
 
-       clts();                 /* Allow maths ops (or we recurse) */
+       clts();                         /* Allow maths ops (or we recurse) */
        restore_fpu_checking(&me->thread.xstate->fxsave);
        task_thread_info(me)->status |= TS_USEDFPU;
        me->fpu_counter++;
@@ -1149,64 +1151,61 @@ EXPORT_SYMBOL_GPL(math_state_restore);
 
 void __init trap_init(void)
 {
-       set_intr_gate(0,&divide_error);
-       set_intr_gate_ist(1,&debug,DEBUG_STACK);
-       set_intr_gate_ist(2,&nmi,NMI_STACK);
-       set_system_gate_ist(3,&int3,DEBUG_STACK); /* int3 can be called from all */
-       set_system_gate(4,&overflow);   /* int4 can be called from all */
-       set_intr_gate(5,&bounds);
-       set_intr_gate(6,&invalid_op);
-       set_intr_gate(7,&device_not_available);
-       set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
-       set_intr_gate(9,&coprocessor_segment_overrun);
-       set_intr_gate(10,&invalid_TSS);
-       set_intr_gate(11,&segment_not_present);
-       set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
-       set_intr_gate(13,&general_protection);
-       set_intr_gate(14,&page_fault);
-       set_intr_gate(15,&spurious_interrupt_bug);
-       set_intr_gate(16,&coprocessor_error);
-       set_intr_gate(17,&alignment_check);
+       set_intr_gate(0, &divide_error);
+       set_intr_gate_ist(1, &debug, DEBUG_STACK);
+       set_intr_gate_ist(2, &nmi, NMI_STACK);
+       set_system_gate_ist(3, &int3, DEBUG_STACK); /* int3 can be called from all */
+       set_system_gate(4, &overflow); /* int4 can be called from all */
+       set_intr_gate(5, &bounds);
+       set_intr_gate(6, &invalid_op);
+       set_intr_gate(7, &device_not_available);
+       set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
+       set_intr_gate(9, &coprocessor_segment_overrun);
+       set_intr_gate(10, &invalid_TSS);
+       set_intr_gate(11, &segment_not_present);
+       set_intr_gate_ist(12, &stack_segment, STACKFAULT_STACK);
+       set_intr_gate(13, &general_protection);
+       set_intr_gate(14, &page_fault);
+       set_intr_gate(15, &spurious_interrupt_bug);
+       set_intr_gate(16, &coprocessor_error);
+       set_intr_gate(17, &alignment_check);
 #ifdef CONFIG_X86_MCE
-       set_intr_gate_ist(18,&machine_check, MCE_STACK); 
+       set_intr_gate_ist(18, &machine_check, MCE_STACK);
 #endif
-       set_intr_gate(19,&simd_coprocessor_error);
+       set_intr_gate(19, &simd_coprocessor_error);
 
 #ifdef CONFIG_IA32_EMULATION
        set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 #endif
-       
        /*
         * initialize the per thread extended state:
         */
-        init_thread_xstate();
+       init_thread_xstate();
        /*
-        * Should be a barrier for any external CPU state.
+        * Should be a barrier for any external CPU state:
         */
        cpu_init();
 }
 
-
 static int __init oops_setup(char *s)
-{ 
+{
        if (!s)
                return -EINVAL;
        if (!strcmp(s, "panic"))
                panic_on_oops = 1;
        return 0;
-} 
+}
 early_param("oops", oops_setup);
 
 static int __init kstack_setup(char *s)
 {
        if (!s)
                return -EINVAL;
-       kstack_depth_to_print = simple_strtoul(s,NULL,0);
+       kstack_depth_to_print = simple_strtoul(s, NULL, 0);
        return 0;
 }
 early_param("kstack", kstack_setup);
 
-
 static int __init code_bytes_setup(char *s)
 {
        code_bytes = simple_strtoul(s, NULL, 0);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
new file mode 100644 (file)
index 0000000..3c36f92
--- /dev/null
@@ -0,0 +1,533 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/acpi_pmtmr.h>
+#include <linux/cpufreq.h>
+#include <linux/dmi.h>
+#include <linux/delay.h>
+#include <linux/clocksource.h>
+#include <linux/percpu.h>
+
+#include <asm/hpet.h>
+#include <asm/timer.h>
+#include <asm/vgtod.h>
+#include <asm/time.h>
+#include <asm/delay.h>
+
+unsigned int cpu_khz;           /* TSC clocks / usec, not used here */
+EXPORT_SYMBOL(cpu_khz);
+unsigned int tsc_khz;
+EXPORT_SYMBOL(tsc_khz);
+
+/*
+ * TSC can be unstable due to cpufreq or due to unsynced TSCs
+ */
+static int tsc_unstable;
+
+/* native_sched_clock() is called before tsc_init(), so
+   we must start with the TSC soft disabled to prevent
+   erroneous rdtsc usage on !cpu_has_tsc processors */
+static int tsc_disabled = -1;
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+u64 native_sched_clock(void)
+{
+       u64 this_offset;
+
+       /*
+        * Fall back to jiffies if there's no TSC available:
+        * ( But note that we still use it if the TSC is marked
+        *   unstable. We do this because unlike Time Of Day,
+        *   the scheduler clock tolerates small errors and it's
+        *   very important for it to be as fast as the platform
+        *   can achive it. )
+        */
+       if (unlikely(tsc_disabled)) {
+               /* No locking but a rare wrong value is not a big deal: */
+               return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
+       }
+
+       /* read the Time Stamp Counter: */
+       rdtscll(this_offset);
+
+       /* return the value in ns */
+       return cycles_2_ns(this_offset);
+}
+
+/* We need to define a real function for sched_clock, to override the
+   weak default version */
+#ifdef CONFIG_PARAVIRT
+unsigned long long sched_clock(void)
+{
+       return paravirt_sched_clock();
+}
+#else
+unsigned long long
+sched_clock(void) __attribute__((alias("native_sched_clock")));
+#endif
+
+int check_tsc_unstable(void)
+{
+       return tsc_unstable;
+}
+EXPORT_SYMBOL_GPL(check_tsc_unstable);
+
+#ifdef CONFIG_X86_TSC
+int __init notsc_setup(char *str)
+{
+       printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
+                       "cannot disable TSC completely.\n");
+       tsc_disabled = 1;
+       return 1;
+}
+#else
+/*
+ * disable flag for tsc. Takes effect by clearing the TSC cpu flag
+ * in cpu/common.c
+ */
+int __init notsc_setup(char *str)
+{
+       setup_clear_cpu_cap(X86_FEATURE_TSC);
+       return 1;
+}
+#endif
+
+__setup("notsc", notsc_setup);
+
+#define MAX_RETRIES     5
+#define SMI_TRESHOLD    50000
+
+/*
+ * Read TSC and the reference counters. Take care of SMI disturbance
+ */
+static u64 __init tsc_read_refs(u64 *pm, u64 *hpet)
+{
+       u64 t1, t2;
+       int i;
+
+       for (i = 0; i < MAX_RETRIES; i++) {
+               t1 = get_cycles();
+               if (hpet)
+                       *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
+               else
+                       *pm = acpi_pm_read_early();
+               t2 = get_cycles();
+               if ((t2 - t1) < SMI_TRESHOLD)
+                       return t2;
+       }
+       return ULLONG_MAX;
+}
+
+/**
+ * native_calibrate_tsc - calibrate the tsc on boot
+ */
+unsigned long native_calibrate_tsc(void)
+{
+       unsigned long flags;
+       u64 tsc1, tsc2, tr1, tr2, delta, pm1, pm2, hpet1, hpet2;
+       int hpet = is_hpet_enabled();
+       unsigned int tsc_khz_val = 0;
+
+       local_irq_save(flags);
+
+       tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
+
+       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+       outb(0xb0, 0x43);
+       outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
+       outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+       tr1 = get_cycles();
+       while ((inb(0x61) & 0x20) == 0);
+       tr2 = get_cycles();
+
+       tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
+
+       local_irq_restore(flags);
+
+       /*
+        * Preset the result with the raw and inaccurate PIT
+        * calibration value
+        */
+       delta = (tr2 - tr1);
+       do_div(delta, 50);
+       tsc_khz_val = delta;
+
+       /* hpet or pmtimer available ? */
+       if (!hpet && !pm1 && !pm2) {
+               printk(KERN_INFO "TSC calibrated against PIT\n");
+               goto out;
+       }
+
+       /* Check, whether the sampling was disturbed by an SMI */
+       if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) {
+               printk(KERN_WARNING "TSC calibration disturbed by SMI, "
+                               "using PIT calibration result\n");
+               goto out;
+       }
+
+       tsc2 = (tsc2 - tsc1) * 1000000LL;
+
+       if (hpet) {
+               printk(KERN_INFO "TSC calibrated against HPET\n");
+               if (hpet2 < hpet1)
+                       hpet2 += 0x100000000ULL;
+               hpet2 -= hpet1;
+               tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD));
+               do_div(tsc1, 1000000);
+       } else {
+               printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
+               if (pm2 < pm1)
+                       pm2 += (u64)ACPI_PM_OVRRUN;
+               pm2 -= pm1;
+               tsc1 = pm2 * 1000000000LL;
+               do_div(tsc1, PMTMR_TICKS_PER_SEC);
+       }
+
+       do_div(tsc2, tsc1);
+       tsc_khz_val = tsc2;
+
+out:
+       return tsc_khz_val;
+}
+
+
+#ifdef CONFIG_X86_32
+/* Only called from the Powernow K7 cpu freq driver */
+int recalibrate_cpu_khz(void)
+{
+#ifndef CONFIG_SMP
+       unsigned long cpu_khz_old = cpu_khz;
+
+       if (cpu_has_tsc) {
+               tsc_khz = calibrate_tsc();
+               cpu_khz = tsc_khz;
+               cpu_data(0).loops_per_jiffy =
+                       cpufreq_scale(cpu_data(0).loops_per_jiffy,
+                                       cpu_khz_old, cpu_khz);
+               return 0;
+       } else
+               return -ENODEV;
+#else
+       return -ENODEV;
+#endif
+}
+
+EXPORT_SYMBOL(recalibrate_cpu_khz);
+
+#endif /* CONFIG_X86_32 */
+
+/* Accelerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ *  basic equation:
+ *              ns = cycles / (freq / ns_per_sec)
+ *              ns = cycles * (ns_per_sec / freq)
+ *              ns = cycles * (10^9 / (cpu_khz * 10^3))
+ *              ns = cycles * (10^6 / cpu_khz)
+ *
+ *      Then we use scaling math (suggested by george@mvista.com) to get:
+ *              ns = cycles * (10^6 * SC / cpu_khz) / SC
+ *              ns = cycles * cyc2ns_scale / SC
+ *
+ *      And since SC is a constant power of two, we can convert the div
+ *  into a shift.
+ *
+ *  We can use khz divisor instead of mhz to keep a better precision, since
+ *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ *  (mathieu.desnoyers@polymtl.ca)
+ *
+ *                      -johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+
+DEFINE_PER_CPU(unsigned long, cyc2ns);
+
+static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
+{
+       unsigned long long tsc_now, ns_now;
+       unsigned long flags, *scale;
+
+       local_irq_save(flags);
+       sched_clock_idle_sleep_event();
+
+       scale = &per_cpu(cyc2ns, cpu);
+
+       rdtscll(tsc_now);
+       ns_now = __cycles_2_ns(tsc_now);
+
+       if (cpu_khz)
+               *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
+
+       sched_clock_idle_wakeup_event(0);
+       local_irq_restore(flags);
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency
+ * changes.
+ *
+ * RED-PEN: On SMP we assume all CPUs run with the same frequency.  It's
+ * not that important because current Opteron setups do not support
+ * scaling on SMP anyroads.
+ *
+ * Should fix up last_tsc too. Currently gettimeofday in the
+ * first tick after the change will be slightly wrong.
+ */
+
+static unsigned int  ref_freq;
+static unsigned long loops_per_jiffy_ref;
+static unsigned long tsc_khz_ref;
+
+static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+                               void *data)
+{
+       struct cpufreq_freqs *freq = data;
+       unsigned long *lpj, dummy;
+
+       if (cpu_has(&cpu_data(freq->cpu), X86_FEATURE_CONSTANT_TSC))
+               return 0;
+
+       lpj = &dummy;
+       if (!(freq->flags & CPUFREQ_CONST_LOOPS))
+#ifdef CONFIG_SMP
+               lpj = &cpu_data(freq->cpu).loops_per_jiffy;
+#else
+       lpj = &boot_cpu_data.loops_per_jiffy;
+#endif
+
+       if (!ref_freq) {
+               ref_freq = freq->old;
+               loops_per_jiffy_ref = *lpj;
+               tsc_khz_ref = tsc_khz;
+       }
+       if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+                       (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+                       (val == CPUFREQ_RESUMECHANGE)) {
+               *lpj =  cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
+
+               tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
+               if (!(freq->flags & CPUFREQ_CONST_LOOPS))
+                       mark_tsc_unstable("cpufreq changes");
+       }
+
+       set_cyc2ns_scale(tsc_khz_ref, freq->cpu);
+
+       return 0;
+}
+
+static struct notifier_block time_cpufreq_notifier_block = {
+       .notifier_call  = time_cpufreq_notifier
+};
+
+static int __init cpufreq_tsc(void)
+{
+       cpufreq_register_notifier(&time_cpufreq_notifier_block,
+                               CPUFREQ_TRANSITION_NOTIFIER);
+       return 0;
+}
+
+core_initcall(cpufreq_tsc);
+
+#endif /* CONFIG_CPU_FREQ */
+
+/* clocksource code */
+
+static struct clocksource clocksource_tsc;
+
+/*
+ * We compare the TSC to the cycle_last value in the clocksource
+ * structure to avoid a nasty time-warp. This can be observed in a
+ * very small window right after one CPU updated cycle_last under
+ * xtime/vsyscall_gtod lock and the other CPU reads a TSC value which
+ * is smaller than the cycle_last reference value due to a TSC which
+ * is slighty behind. This delta is nowhere else observable, but in
+ * that case it results in a forward time jump in the range of hours
+ * due to the unsigned delta calculation of the time keeping core
+ * code, which is necessary to support wrapping clocksources like pm
+ * timer.
+ */
+static cycle_t read_tsc(void)
+{
+       cycle_t ret = (cycle_t)get_cycles();
+
+       return ret >= clocksource_tsc.cycle_last ?
+               ret : clocksource_tsc.cycle_last;
+}
+
+static cycle_t __vsyscall_fn vread_tsc(void)
+{
+       cycle_t ret = (cycle_t)vget_cycles();
+
+       return ret >= __vsyscall_gtod_data.clock.cycle_last ?
+               ret : __vsyscall_gtod_data.clock.cycle_last;
+}
+
+static struct clocksource clocksource_tsc = {
+       .name                   = "tsc",
+       .rating                 = 300,
+       .read                   = read_tsc,
+       .mask                   = CLOCKSOURCE_MASK(64),
+       .shift                  = 22,
+       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
+                                 CLOCK_SOURCE_MUST_VERIFY,
+#ifdef CONFIG_X86_64
+       .vread                  = vread_tsc,
+#endif
+};
+
+void mark_tsc_unstable(char *reason)
+{
+       if (!tsc_unstable) {
+               tsc_unstable = 1;
+               printk("Marking TSC unstable due to %s\n", reason);
+               /* Change only the rating, when not registered */
+               if (clocksource_tsc.mult)
+                       clocksource_change_rating(&clocksource_tsc, 0);
+               else
+                       clocksource_tsc.rating = 0;
+       }
+}
+
+EXPORT_SYMBOL_GPL(mark_tsc_unstable);
+
+static int __init dmi_mark_tsc_unstable(const struct dmi_system_id *d)
+{
+       printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
+                       d->ident);
+       tsc_unstable = 1;
+       return 0;
+}
+
+/* List of systems that have known TSC problems */
+static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
+       {
+               .callback = dmi_mark_tsc_unstable,
+               .ident = "IBM Thinkpad 380XD",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+                       DMI_MATCH(DMI_BOARD_NAME, "2635FA0"),
+               },
+       },
+       {}
+};
+
+/*
+ * Geode_LX - the OLPC CPU has a possibly a very reliable TSC
+ */
+#ifdef CONFIG_MGEODE_LX
+/* RTSC counts during suspend */
+#define RTSC_SUSP 0x100
+
+static void __init check_geode_tsc_reliable(void)
+{
+       unsigned long res_low, res_high;
+
+       rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high);
+       if (res_low & RTSC_SUSP)
+               clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
+}
+#else
+static inline void check_geode_tsc_reliable(void) { }
+#endif
+
+/*
+ * Make an educated guess if the TSC is trustworthy and synchronized
+ * over all CPUs.
+ */
+__cpuinit int unsynchronized_tsc(void)
+{
+       if (!cpu_has_tsc || tsc_unstable)
+               return 1;
+
+#ifdef CONFIG_SMP
+       if (apic_is_clustered_box())
+               return 1;
+#endif
+
+       if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+               return 0;
+       /*
+        * Intel systems are normally all synchronized.
+        * Exceptions must mark TSC as unstable:
+        */
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+               /* assume multi socket systems are not synchronized: */
+               if (num_possible_cpus() > 1)
+                       tsc_unstable = 1;
+       }
+
+       return tsc_unstable;
+}
+
+static void __init init_tsc_clocksource(void)
+{
+       clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
+                       clocksource_tsc.shift);
+       /* lower the rating if we already know its unstable: */
+       if (check_tsc_unstable()) {
+               clocksource_tsc.rating = 0;
+               clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
+       }
+       clocksource_register(&clocksource_tsc);
+}
+
+void __init tsc_init(void)
+{
+       u64 lpj;
+       int cpu;
+
+       if (!cpu_has_tsc)
+               return;
+
+       tsc_khz = calibrate_tsc();
+       cpu_khz = tsc_khz;
+
+       if (!tsc_khz) {
+               mark_tsc_unstable("could not calculate TSC khz");
+               return;
+       }
+
+#ifdef CONFIG_X86_64
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
+                       (boot_cpu_data.x86_vendor == X86_VENDOR_AMD))
+               cpu_khz = calibrate_cpu();
+#endif
+
+       lpj = ((u64)tsc_khz * 1000);
+       do_div(lpj, HZ);
+       lpj_fine = lpj;
+
+       printk("Detected %lu.%03lu MHz processor.\n",
+                       (unsigned long)cpu_khz / 1000,
+                       (unsigned long)cpu_khz % 1000);
+
+       /*
+        * Secondary CPUs do not run through tsc_init(), so set up
+        * all the scale factors for all CPUs, assuming the same
+        * speed as the bootup CPU. (cpufreq notifiers will fix this
+        * up if their speed diverges)
+        */
+       for_each_possible_cpu(cpu)
+               set_cyc2ns_scale(cpu_khz, cpu);
+
+       if (tsc_disabled > 0)
+               return;
+
+       /* now allow native_sched_clock() to use rdtsc */
+       tsc_disabled = 0;
+
+       use_tsc_delay();
+       /* Check and install the TSC clocksource */
+       dmi_check_system(bad_tsc_dmi_table);
+
+       if (unsynchronized_tsc())
+               mark_tsc_unstable("TSCs unsynchronized");
+
+       check_geode_tsc_reliable();
+       init_tsc_clocksource();
+}
+
diff --git a/arch/x86/kernel/tsc_32.c b/arch/x86/kernel/tsc_32.c
deleted file mode 100644 (file)
index 65b7063..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-#include <linux/sched.h>
-#include <linux/clocksource.h>
-#include <linux/workqueue.h>
-#include <linux/cpufreq.h>
-#include <linux/jiffies.h>
-#include <linux/init.h>
-#include <linux/dmi.h>
-#include <linux/percpu.h>
-
-#include <asm/delay.h>
-#include <asm/tsc.h>
-#include <asm/io.h>
-#include <asm/timer.h>
-
-#include "mach_timer.h"
-
-/* native_sched_clock() is called before tsc_init(), so
-   we must start with the TSC soft disabled to prevent
-   erroneous rdtsc usage on !cpu_has_tsc processors */
-static int tsc_disabled = -1;
-
-/*
- * On some systems the TSC frequency does not
- * change with the cpu frequency. So we need
- * an extra value to store the TSC freq
- */
-unsigned int tsc_khz;
-EXPORT_SYMBOL_GPL(tsc_khz);
-
-#ifdef CONFIG_X86_TSC
-static int __init tsc_setup(char *str)
-{
-       printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
-              "cannot disable TSC completely.\n");
-       tsc_disabled = 1;
-       return 1;
-}
-#else
-/*
- * disable flag for tsc. Takes effect by clearing the TSC cpu flag
- * in cpu/common.c
- */
-static int __init tsc_setup(char *str)
-{
-       setup_clear_cpu_cap(X86_FEATURE_TSC);
-       return 1;
-}
-#endif
-
-__setup("notsc", tsc_setup);
-
-/*
- * code to mark and check if the TSC is unstable
- * due to cpufreq or due to unsynced TSCs
- */
-static int tsc_unstable;
-
-int check_tsc_unstable(void)
-{
-       return tsc_unstable;
-}
-EXPORT_SYMBOL_GPL(check_tsc_unstable);
-
-/* Accelerators for sched_clock()
- * convert from cycles(64bits) => nanoseconds (64bits)
- *  basic equation:
- *             ns = cycles / (freq / ns_per_sec)
- *             ns = cycles * (ns_per_sec / freq)
- *             ns = cycles * (10^9 / (cpu_khz * 10^3))
- *             ns = cycles * (10^6 / cpu_khz)
- *
- *     Then we use scaling math (suggested by george@mvista.com) to get:
- *             ns = cycles * (10^6 * SC / cpu_khz) / SC
- *             ns = cycles * cyc2ns_scale / SC
- *
- *     And since SC is a constant power of two, we can convert the div
- *  into a shift.
- *
- *  We can use khz divisor instead of mhz to keep a better precision, since
- *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- *  (mathieu.desnoyers@polymtl.ca)
- *
- *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-
-DEFINE_PER_CPU(unsigned long, cyc2ns);
-
-static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
-{
-       unsigned long long tsc_now, ns_now;
-       unsigned long flags, *scale;
-
-       local_irq_save(flags);
-       sched_clock_idle_sleep_event();
-
-       scale = &per_cpu(cyc2ns, cpu);
-
-       rdtscll(tsc_now);
-       ns_now = __cycles_2_ns(tsc_now);
-
-       if (cpu_khz)
-               *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
-
-       /*
-        * Start smoothly with the new frequency:
-        */
-       sched_clock_idle_wakeup_event(0);
-       local_irq_restore(flags);
-}
-
-/*
- * Scheduler clock - returns current time in nanosec units.
- */
-unsigned long long native_sched_clock(void)
-{
-       unsigned long long this_offset;
-
-       /*
-        * Fall back to jiffies if there's no TSC available:
-        * ( But note that we still use it if the TSC is marked
-        *   unstable. We do this because unlike Time Of Day,
-        *   the scheduler clock tolerates small errors and it's
-        *   very important for it to be as fast as the platform
-        *   can achive it. )
-        */
-       if (unlikely(tsc_disabled))
-               /* No locking but a rare wrong value is not a big deal: */
-               return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
-
-       /* read the Time Stamp Counter: */
-       rdtscll(this_offset);
-
-       /* return the value in ns */
-       return cycles_2_ns(this_offset);
-}
-
-/* We need to define a real function for sched_clock, to override the
-   weak default version */
-#ifdef CONFIG_PARAVIRT
-unsigned long long sched_clock(void)
-{
-       return paravirt_sched_clock();
-}
-#else
-unsigned long long sched_clock(void)
-       __attribute__((alias("native_sched_clock")));
-#endif
-
-unsigned long native_calculate_cpu_khz(void)
-{
-       unsigned long long start, end;
-       unsigned long count;
-       u64 delta64 = (u64)ULLONG_MAX;
-       int i;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       /* run 3 times to ensure the cache is warm and to get an accurate reading */
-       for (i = 0; i < 3; i++) {
-               mach_prepare_counter();
-               rdtscll(start);
-               mach_countup(&count);
-               rdtscll(end);
-
-               /*
-                * Error: ECTCNEVERSET
-                * The CTC wasn't reliable: we got a hit on the very first read,
-                * or the CPU was so fast/slow that the quotient wouldn't fit in
-                * 32 bits..
-                */
-               if (count <= 1)
-                       continue;
-
-               /* cpu freq too slow: */
-               if ((end - start) <= CALIBRATE_TIME_MSEC)
-                       continue;
-
-               /*
-                * We want the minimum time of all runs in case one of them
-                * is inaccurate due to SMI or other delay
-                */
-               delta64 = min(delta64, (end - start));
-       }
-
-       /* cpu freq too fast (or every run was bad): */
-       if (delta64 > (1ULL<<32))
-               goto err;
-
-       delta64 += CALIBRATE_TIME_MSEC/2; /* round for do_div */
-       do_div(delta64,CALIBRATE_TIME_MSEC);
-
-       local_irq_restore(flags);
-       return (unsigned long)delta64;
-err:
-       local_irq_restore(flags);
-       return 0;
-}
-
-int recalibrate_cpu_khz(void)
-{
-#ifndef CONFIG_SMP
-       unsigned long cpu_khz_old = cpu_khz;
-
-       if (cpu_has_tsc) {
-               cpu_khz = calculate_cpu_khz();
-               tsc_khz = cpu_khz;
-               cpu_data(0).loops_per_jiffy =
-                       cpufreq_scale(cpu_data(0).loops_per_jiffy,
-                                       cpu_khz_old, cpu_khz);
-               return 0;
-       } else
-               return -ENODEV;
-#else
-       return -ENODEV;
-#endif
-}
-
-EXPORT_SYMBOL(recalibrate_cpu_khz);
-
-#ifdef CONFIG_CPU_FREQ
-
-/*
- * if the CPU frequency is scaled, TSC-based delays will need a different
- * loops_per_jiffy value to function properly.
- */
-static unsigned int ref_freq;
-static unsigned long loops_per_jiffy_ref;
-static unsigned long cpu_khz_ref;
-
-static int
-time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
-{
-       struct cpufreq_freqs *freq = data;
-
-       if (!ref_freq) {
-               if (!freq->old){
-                       ref_freq = freq->new;
-                       return 0;
-               }
-               ref_freq = freq->old;
-               loops_per_jiffy_ref = cpu_data(freq->cpu).loops_per_jiffy;
-               cpu_khz_ref = cpu_khz;
-       }
-
-       if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
-           (val == CPUFREQ_RESUMECHANGE)) {
-               if (!(freq->flags & CPUFREQ_CONST_LOOPS))
-                       cpu_data(freq->cpu).loops_per_jiffy =
-                               cpufreq_scale(loops_per_jiffy_ref,
-                                               ref_freq, freq->new);
-
-               if (cpu_khz) {
-
-                       if (num_online_cpus() == 1)
-                               cpu_khz = cpufreq_scale(cpu_khz_ref,
-                                               ref_freq, freq->new);
-                       if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
-                               tsc_khz = cpu_khz;
-                               set_cyc2ns_scale(cpu_khz, freq->cpu);
-                               /*
-                                * TSC based sched_clock turns
-                                * to junk w/ cpufreq
-                                */
-                               mark_tsc_unstable("cpufreq changes");
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static struct notifier_block time_cpufreq_notifier_block = {
-       .notifier_call  = time_cpufreq_notifier
-};
-
-static int __init cpufreq_tsc(void)
-{
-       return cpufreq_register_notifier(&time_cpufreq_notifier_block,
-                                        CPUFREQ_TRANSITION_NOTIFIER);
-}
-core_initcall(cpufreq_tsc);
-
-#endif
-
-/* clock source code */
-
-static unsigned long current_tsc_khz;
-static struct clocksource clocksource_tsc;
-
-/*
- * We compare the TSC to the cycle_last value in the clocksource
- * structure to avoid a nasty time-warp issue. This can be observed in
- * a very small window right after one CPU updated cycle_last under
- * xtime lock and the other CPU reads a TSC value which is smaller
- * than the cycle_last reference value due to a TSC which is slighty
- * behind. This delta is nowhere else observable, but in that case it
- * results in a forward time jump in the range of hours due to the
- * unsigned delta calculation of the time keeping core code, which is
- * necessary to support wrapping clocksources like pm timer.
- */
-static cycle_t read_tsc(void)
-{
-       cycle_t ret;
-
-       rdtscll(ret);
-
-       return ret >= clocksource_tsc.cycle_last ?
-               ret : clocksource_tsc.cycle_last;
-}
-
-static struct clocksource clocksource_tsc = {
-       .name                   = "tsc",
-       .rating                 = 300,
-       .read                   = read_tsc,
-       .mask                   = CLOCKSOURCE_MASK(64),
-       .mult                   = 0, /* to be set */
-       .shift                  = 22,
-       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
-                                 CLOCK_SOURCE_MUST_VERIFY,
-};
-
-void mark_tsc_unstable(char *reason)
-{
-       if (!tsc_unstable) {
-               tsc_unstable = 1;
-               printk("Marking TSC unstable due to: %s.\n", reason);
-               /* Can be called before registration */
-               if (clocksource_tsc.mult)
-                       clocksource_change_rating(&clocksource_tsc, 0);
-               else
-                       clocksource_tsc.rating = 0;
-       }
-}
-EXPORT_SYMBOL_GPL(mark_tsc_unstable);
-
-static int __init dmi_mark_tsc_unstable(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
-              d->ident);
-       tsc_unstable = 1;
-       return 0;
-}
-
-/* List of systems that have known TSC problems */
-static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
-       {
-        .callback = dmi_mark_tsc_unstable,
-        .ident = "IBM Thinkpad 380XD",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
-                    DMI_MATCH(DMI_BOARD_NAME, "2635FA0"),
-                    },
-        },
-        {}
-};
-
-/*
- * Make an educated guess if the TSC is trustworthy and synchronized
- * over all CPUs.
- */
-__cpuinit int unsynchronized_tsc(void)
-{
-       if (!cpu_has_tsc || tsc_unstable)
-               return 1;
-
-       /* Anything with constant TSC should be synchronized */
-       if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
-               return 0;
-
-       /*
-        * Intel systems are normally all synchronized.
-        * Exceptions must mark TSC as unstable:
-        */
-       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
-               /* assume multi socket systems are not synchronized: */
-               if (num_possible_cpus() > 1)
-                       tsc_unstable = 1;
-       }
-       return tsc_unstable;
-}
-
-/*
- * Geode_LX - the OLPC CPU has a possibly a very reliable TSC
- */
-#ifdef CONFIG_MGEODE_LX
-/* RTSC counts during suspend */
-#define RTSC_SUSP 0x100
-
-static void __init check_geode_tsc_reliable(void)
-{
-       unsigned long res_low, res_high;
-
-       rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high);
-       if (res_low & RTSC_SUSP)
-               clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
-}
-#else
-static inline void check_geode_tsc_reliable(void) { }
-#endif
-
-
-void __init tsc_init(void)
-{
-       int cpu;
-
-       if (!cpu_has_tsc || tsc_disabled > 0)
-               return;
-
-       cpu_khz = calculate_cpu_khz();
-       tsc_khz = cpu_khz;
-
-       if (!cpu_khz) {
-               mark_tsc_unstable("could not calculate TSC khz");
-               return;
-       }
-
-       /* now allow native_sched_clock() to use rdtsc */
-       tsc_disabled = 0;
-
-       printk("Detected %lu.%03lu MHz processor.\n",
-                               (unsigned long)cpu_khz / 1000,
-                               (unsigned long)cpu_khz % 1000);
-
-       /*
-        * Secondary CPUs do not run through tsc_init(), so set up
-        * all the scale factors for all CPUs, assuming the same
-        * speed as the bootup CPU. (cpufreq notifiers will fix this
-        * up if their speed diverges)
-        */
-       for_each_possible_cpu(cpu)
-               set_cyc2ns_scale(cpu_khz, cpu);
-
-       use_tsc_delay();
-
-       /* Check and install the TSC clocksource */
-       dmi_check_system(bad_tsc_dmi_table);
-
-       unsynchronized_tsc();
-       check_geode_tsc_reliable();
-       current_tsc_khz = tsc_khz;
-       clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
-                                                       clocksource_tsc.shift);
-       /* lower the rating if we already know its unstable: */
-       if (check_tsc_unstable()) {
-               clocksource_tsc.rating = 0;
-               clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
-       }
-       clocksource_register(&clocksource_tsc);
-}
diff --git a/arch/x86/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c
deleted file mode 100644 (file)
index 1784b80..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/clocksource.h>
-#include <linux/time.h>
-#include <linux/acpi.h>
-#include <linux/cpufreq.h>
-#include <linux/acpi_pmtmr.h>
-
-#include <asm/hpet.h>
-#include <asm/timex.h>
-#include <asm/timer.h>
-#include <asm/vgtod.h>
-
-static int notsc __initdata = 0;
-
-unsigned int cpu_khz;          /* TSC clocks / usec, not used here */
-EXPORT_SYMBOL(cpu_khz);
-unsigned int tsc_khz;
-EXPORT_SYMBOL(tsc_khz);
-
-/* Accelerators for sched_clock()
- * convert from cycles(64bits) => nanoseconds (64bits)
- *  basic equation:
- *             ns = cycles / (freq / ns_per_sec)
- *             ns = cycles * (ns_per_sec / freq)
- *             ns = cycles * (10^9 / (cpu_khz * 10^3))
- *             ns = cycles * (10^6 / cpu_khz)
- *
- *     Then we use scaling math (suggested by george@mvista.com) to get:
- *             ns = cycles * (10^6 * SC / cpu_khz) / SC
- *             ns = cycles * cyc2ns_scale / SC
- *
- *     And since SC is a constant power of two, we can convert the div
- *  into a shift.
- *
- *  We can use khz divisor instead of mhz to keep a better precision, since
- *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- *  (mathieu.desnoyers@polymtl.ca)
- *
- *                     -johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-DEFINE_PER_CPU(unsigned long, cyc2ns);
-
-static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
-{
-       unsigned long long tsc_now, ns_now;
-       unsigned long flags, *scale;
-
-       local_irq_save(flags);
-       sched_clock_idle_sleep_event();
-
-       scale = &per_cpu(cyc2ns, cpu);
-
-       rdtscll(tsc_now);
-       ns_now = __cycles_2_ns(tsc_now);
-
-       if (cpu_khz)
-               *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
-
-       sched_clock_idle_wakeup_event(0);
-       local_irq_restore(flags);
-}
-
-unsigned long long native_sched_clock(void)
-{
-       unsigned long a = 0;
-
-       /* Could do CPU core sync here. Opteron can execute rdtsc speculatively,
-        * which means it is not completely exact and may not be monotonous
-        * between CPUs. But the errors should be too small to matter for
-        * scheduling purposes.
-        */
-
-       rdtscll(a);
-       return cycles_2_ns(a);
-}
-
-/* We need to define a real function for sched_clock, to override the
-   weak default version */
-#ifdef CONFIG_PARAVIRT
-unsigned long long sched_clock(void)
-{
-       return paravirt_sched_clock();
-}
-#else
-unsigned long long
-sched_clock(void) __attribute__((alias("native_sched_clock")));
-#endif
-
-
-static int tsc_unstable;
-
-int check_tsc_unstable(void)
-{
-       return tsc_unstable;
-}
-EXPORT_SYMBOL_GPL(check_tsc_unstable);
-
-#ifdef CONFIG_CPU_FREQ
-
-/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency
- * changes.
- *
- * RED-PEN: On SMP we assume all CPUs run with the same frequency.  It's
- * not that important because current Opteron setups do not support
- * scaling on SMP anyroads.
- *
- * Should fix up last_tsc too. Currently gettimeofday in the
- * first tick after the change will be slightly wrong.
- */
-
-static unsigned int  ref_freq;
-static unsigned long loops_per_jiffy_ref;
-static unsigned long tsc_khz_ref;
-
-static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-                                void *data)
-{
-       struct cpufreq_freqs *freq = data;
-       unsigned long *lpj, dummy;
-
-       if (cpu_has(&cpu_data(freq->cpu), X86_FEATURE_CONSTANT_TSC))
-               return 0;
-
-       lpj = &dummy;
-       if (!(freq->flags & CPUFREQ_CONST_LOOPS))
-#ifdef CONFIG_SMP
-               lpj = &cpu_data(freq->cpu).loops_per_jiffy;
-#else
-               lpj = &boot_cpu_data.loops_per_jiffy;
-#endif
-
-       if (!ref_freq) {
-               ref_freq = freq->old;
-               loops_per_jiffy_ref = *lpj;
-               tsc_khz_ref = tsc_khz;
-       }
-       if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
-               (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
-               (val == CPUFREQ_RESUMECHANGE)) {
-               *lpj =
-               cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
-
-               tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
-               if (!(freq->flags & CPUFREQ_CONST_LOOPS))
-                       mark_tsc_unstable("cpufreq changes");
-       }
-
-       set_cyc2ns_scale(tsc_khz_ref, freq->cpu);
-
-       return 0;
-}
-
-static struct notifier_block time_cpufreq_notifier_block = {
-       .notifier_call  = time_cpufreq_notifier
-};
-
-static int __init cpufreq_tsc(void)
-{
-       cpufreq_register_notifier(&time_cpufreq_notifier_block,
-                                 CPUFREQ_TRANSITION_NOTIFIER);
-       return 0;
-}
-
-core_initcall(cpufreq_tsc);
-
-#endif
-
-#define MAX_RETRIES    5
-#define SMI_TRESHOLD   50000
-
-/*
- * Read TSC and the reference counters. Take care of SMI disturbance
- */
-static unsigned long __init tsc_read_refs(unsigned long *pm,
-                                         unsigned long *hpet)
-{
-       unsigned long t1, t2;
-       int i;
-
-       for (i = 0; i < MAX_RETRIES; i++) {
-               t1 = get_cycles();
-               if (hpet)
-                       *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
-               else
-                       *pm = acpi_pm_read_early();
-               t2 = get_cycles();
-               if ((t2 - t1) < SMI_TRESHOLD)
-                       return t2;
-       }
-       return ULONG_MAX;
-}
-
-/**
- * tsc_calibrate - calibrate the tsc on boot
- */
-void __init tsc_calibrate(void)
-{
-       unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2;
-       int hpet = is_hpet_enabled(), cpu;
-
-       local_irq_save(flags);
-
-       tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
-
-       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
-       outb(0xb0, 0x43);
-       outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
-       outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
-       tr1 = get_cycles();
-       while ((inb(0x61) & 0x20) == 0);
-       tr2 = get_cycles();
-
-       tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
-
-       local_irq_restore(flags);
-
-       /*
-        * Preset the result with the raw and inaccurate PIT
-        * calibration value
-        */
-       tsc_khz = (tr2 - tr1) / 50;
-
-       /* hpet or pmtimer available ? */
-       if (!hpet && !pm1 && !pm2) {
-               printk(KERN_INFO "TSC calibrated against PIT\n");
-               goto out;
-       }
-
-       /* Check, whether the sampling was disturbed by an SMI */
-       if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) {
-               printk(KERN_WARNING "TSC calibration disturbed by SMI, "
-                      "using PIT calibration result\n");
-               goto out;
-       }
-
-       tsc2 = (tsc2 - tsc1) * 1000000L;
-
-       if (hpet) {
-               printk(KERN_INFO "TSC calibrated against HPET\n");
-               if (hpet2 < hpet1)
-                       hpet2 += 0x100000000;
-               hpet2 -= hpet1;
-               tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000;
-       } else {
-               printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
-               if (pm2 < pm1)
-                       pm2 += ACPI_PM_OVRRUN;
-               pm2 -= pm1;
-               tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC;
-       }
-
-       tsc_khz = tsc2 / tsc1;
-
-out:
-       for_each_possible_cpu(cpu)
-               set_cyc2ns_scale(tsc_khz, cpu);
-}
-
-/*
- * Make an educated guess if the TSC is trustworthy and synchronized
- * over all CPUs.
- */
-__cpuinit int unsynchronized_tsc(void)
-{
-       if (tsc_unstable)
-               return 1;
-
-#ifdef CONFIG_SMP
-       if (apic_is_clustered_box())
-               return 1;
-#endif
-
-       if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
-               return 0;
-
-       /* Assume multi socket systems are not synchronized */
-       return num_present_cpus() > 1;
-}
-
-int __init notsc_setup(char *s)
-{
-       notsc = 1;
-       return 1;
-}
-
-__setup("notsc", notsc_setup);
-
-static struct clocksource clocksource_tsc;
-
-/*
- * We compare the TSC to the cycle_last value in the clocksource
- * structure to avoid a nasty time-warp. This can be observed in a
- * very small window right after one CPU updated cycle_last under
- * xtime/vsyscall_gtod lock and the other CPU reads a TSC value which
- * is smaller than the cycle_last reference value due to a TSC which
- * is slighty behind. This delta is nowhere else observable, but in
- * that case it results in a forward time jump in the range of hours
- * due to the unsigned delta calculation of the time keeping core
- * code, which is necessary to support wrapping clocksources like pm
- * timer.
- */
-static cycle_t read_tsc(void)
-{
-       cycle_t ret = (cycle_t)get_cycles();
-
-       return ret >= clocksource_tsc.cycle_last ?
-               ret : clocksource_tsc.cycle_last;
-}
-
-static cycle_t __vsyscall_fn vread_tsc(void)
-{
-       cycle_t ret = (cycle_t)vget_cycles();
-
-       return ret >= __vsyscall_gtod_data.clock.cycle_last ?
-               ret : __vsyscall_gtod_data.clock.cycle_last;
-}
-
-static struct clocksource clocksource_tsc = {
-       .name                   = "tsc",
-       .rating                 = 300,
-       .read                   = read_tsc,
-       .mask                   = CLOCKSOURCE_MASK(64),
-       .shift                  = 22,
-       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
-                                 CLOCK_SOURCE_MUST_VERIFY,
-       .vread                  = vread_tsc,
-};
-
-void mark_tsc_unstable(char *reason)
-{
-       if (!tsc_unstable) {
-               tsc_unstable = 1;
-               printk("Marking TSC unstable due to %s\n", reason);
-               /* Change only the rating, when not registered */
-               if (clocksource_tsc.mult)
-                       clocksource_change_rating(&clocksource_tsc, 0);
-               else
-                       clocksource_tsc.rating = 0;
-       }
-}
-EXPORT_SYMBOL_GPL(mark_tsc_unstable);
-
-void __init init_tsc_clocksource(void)
-{
-       if (!notsc) {
-               clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
-                                                       clocksource_tsc.shift);
-               if (check_tsc_unstable())
-                       clocksource_tsc.rating = 0;
-
-               clocksource_register(&clocksource_tsc);
-       }
-}
diff --git a/arch/x86/kernel/visws_quirks.c b/arch/x86/kernel/visws_quirks.c
new file mode 100644 (file)
index 0000000..e94bdb6
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ *  SGI Visual Workstation support and quirks, unmaintained.
+ *
+ *  Split out from setup.c by davej@suse.de
+ *
+ *     Copyright (C) 1999 Bent Hagemark, Ingo Molnar
+ *
+ *  SGI Visual Workstation interrupt controller
+ *
+ *  The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
+ *  which serves as the main interrupt controller in the system.  Non-legacy
+ *  hardware in the system uses this controller directly.  Legacy devices
+ *  are connected to the PIIX4 which in turn has its 8259(s) connected to
+ *  a of the Cobalt APIC entry.
+ *
+ *  09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
+ *
+ *  25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/visws/cobalt.h>
+#include <asm/visws/piix4.h>
+#include <asm/arch_hooks.h>
+#include <asm/fixmap.h>
+#include <asm/reboot.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/smp.h>
+#include <asm/io.h>
+
+#include <mach_ipi.h>
+
+#include "mach_apic.h"
+
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/i8259.h>
+#include <asm/irq_vectors.h>
+#include <asm/visws/cobalt.h>
+#include <asm/visws/lithium.h>
+#include <asm/visws/piix4.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+extern int no_broadcast;
+
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/arch_hooks.h>
+#include <asm/visws/cobalt.h>
+#include <asm/visws/lithium.h>
+
+char visws_board_type  = -1;
+char visws_board_rev   = -1;
+
+int is_visws_box(void)
+{
+       return visws_board_type >= 0;
+}
+
+static int __init visws_time_init_quirk(void)
+{
+       printk(KERN_INFO "Starting Cobalt Timer system clock\n");
+
+       /* Set the countdown value */
+       co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
+
+       /* Start the timer */
+       co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
+
+       /* Enable (unmask) the timer interrupt */
+       co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
+
+       /*
+        * Zero return means the generic timer setup code will set up
+        * the standard vector:
+        */
+       return 0;
+}
+
+static int __init visws_pre_intr_init_quirk(void)
+{
+       init_VISWS_APIC_irqs();
+
+       /*
+        * We dont want ISA irqs to be set up by the generic code:
+        */
+       return 1;
+}
+
+/* Quirk for machine specific memory setup. */
+
+#define MB (1024 * 1024)
+
+unsigned long sgivwfb_mem_phys;
+unsigned long sgivwfb_mem_size;
+EXPORT_SYMBOL(sgivwfb_mem_phys);
+EXPORT_SYMBOL(sgivwfb_mem_size);
+
+long long mem_size __initdata = 0;
+
+static char * __init visws_memory_setup_quirk(void)
+{
+       long long gfx_mem_size = 8 * MB;
+
+       mem_size = boot_params.alt_mem_k;
+
+       if (!mem_size) {
+               printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
+               mem_size = 128 * MB;
+       }
+
+       /*
+        * this hardcodes the graphics memory to 8 MB
+        * it really should be sized dynamically (or at least
+        * set as a boot param)
+        */
+       if (!sgivwfb_mem_size) {
+               printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
+               sgivwfb_mem_size = 8 * MB;
+       }
+
+       /*
+        * Trim to nearest MB
+        */
+       sgivwfb_mem_size &= ~((1 << 20) - 1);
+       sgivwfb_mem_phys = mem_size - gfx_mem_size;
+
+       e820_add_region(0, LOWMEMSIZE(), E820_RAM);
+       e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
+       e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
+
+       return "PROM";
+}
+
+static void visws_machine_emergency_restart(void)
+{
+       /*
+        * Visual Workstations restart after this
+        * register is poked on the PIIX4
+        */
+       outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
+}
+
+static void visws_machine_power_off(void)
+{
+       unsigned short pm_status;
+/*     extern unsigned int pci_bus0; */
+
+       while ((pm_status = inw(PMSTS_PORT)) & 0x100)
+               outw(pm_status, PMSTS_PORT);
+
+       outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
+
+       mdelay(10);
+
+#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
+       (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
+
+/*     outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */
+       outl(PIIX_SPECIAL_STOP, 0xCFC);
+}
+
+static int __init visws_get_smp_config_quirk(unsigned int early)
+{
+       /*
+        * Prevent MP-table parsing by the generic code:
+        */
+       return 1;
+}
+
+extern unsigned int __cpuinitdata maxcpus;
+
+/*
+ * The Visual Workstation is Intel MP compliant in the hardware
+ * sense, but it doesn't have a BIOS(-configuration table).
+ * No problem for Linux.
+ */
+
+static void __init MP_processor_info (struct mpc_config_processor *m)
+{
+       int ver, logical_apicid;
+       physid_mask_t apic_cpus;
+
+       if (!(m->mpc_cpuflag & CPU_ENABLED))
+               return;
+
+       logical_apicid = m->mpc_apicid;
+       printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
+              m->mpc_cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
+              m->mpc_apicid,
+              (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
+              (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
+              m->mpc_apicver);
+
+       if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
+               boot_cpu_physical_apicid = m->mpc_apicid;
+
+       ver = m->mpc_apicver;
+       if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
+               printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
+                       m->mpc_apicid, MAX_APICS);
+               return;
+       }
+
+       apic_cpus = apicid_to_cpu_present(m->mpc_apicid);
+       physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
+       /*
+        * Validate version
+        */
+       if (ver == 0x0) {
+               printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
+                       "fixing up to 0x10. (tell your hw vendor)\n",
+                       m->mpc_apicid);
+               ver = 0x10;
+       }
+       apic_version[m->mpc_apicid] = ver;
+}
+
+int __init visws_find_smp_config_quirk(unsigned int reserve)
+{
+       struct mpc_config_processor *mp = phys_to_virt(CO_CPU_TAB_PHYS);
+       unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
+
+       if (ncpus > CO_CPU_MAX) {
+               printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
+                       ncpus, mp);
+
+               ncpus = CO_CPU_MAX;
+       }
+
+       if (ncpus > maxcpus)
+               ncpus = maxcpus;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+       smp_found_config = 1;
+#endif
+       while (ncpus--)
+               MP_processor_info(mp++);
+
+       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+       return 1;
+}
+
+extern int visws_trap_init_quirk(void);
+
+void __init visws_early_detect(void)
+{
+       int raw;
+
+       visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
+                                                        >> PIIX_GPI_BD_SHIFT;
+
+       if (visws_board_type < 0)
+               return;
+
+       /*
+        * Install special quirks for timer, interrupt and memory setup:
+        */
+       arch_time_init_quirk            = visws_time_init_quirk;
+       arch_pre_intr_init_quirk        = visws_pre_intr_init_quirk;
+       arch_memory_setup_quirk         = visws_memory_setup_quirk;
+
+       /*
+        * Fall back to generic behavior for traps:
+        */
+       arch_intr_init_quirk            = NULL;
+       arch_trap_init_quirk            = visws_trap_init_quirk;
+
+       /*
+        * Install reboot quirks:
+        */
+       pm_power_off                    = visws_machine_power_off;
+       machine_ops.emergency_restart   = visws_machine_emergency_restart;
+
+       /*
+        * Do not use broadcast IPIs:
+        */
+       no_broadcast = 0;
+
+       /*
+        * Override generic MP-table parsing:
+        */
+       mach_get_smp_config_quirk       = visws_get_smp_config_quirk;
+       mach_find_smp_config_quirk      = visws_find_smp_config_quirk;
+
+#ifdef CONFIG_X86_IO_APIC
+       /*
+        * Turn off IO-APIC detection and initialization:
+        */
+       skip_ioapic_setup               = 1;
+#endif
+
+       /*
+        * Get Board rev.
+        * First, we have to initialize the 307 part to allow us access
+        * to the GPIO registers.  Let's map them at 0x0fc0 which is right
+        * after the PIIX4 PM section.
+        */
+       outb_p(SIO_DEV_SEL, SIO_INDEX);
+       outb_p(SIO_GP_DEV, SIO_DATA);   /* Talk to GPIO regs. */
+
+       outb_p(SIO_DEV_MSB, SIO_INDEX);
+       outb_p(SIO_GP_MSB, SIO_DATA);   /* MSB of GPIO base address */
+
+       outb_p(SIO_DEV_LSB, SIO_INDEX);
+       outb_p(SIO_GP_LSB, SIO_DATA);   /* LSB of GPIO base address */
+
+       outb_p(SIO_DEV_ENB, SIO_INDEX);
+       outb_p(1, SIO_DATA);            /* Enable GPIO registers. */
+
+       /*
+        * Now, we have to map the power management section to write
+        * a bit which enables access to the GPIO registers.
+        * What lunatic came up with this shit?
+        */
+       outb_p(SIO_DEV_SEL, SIO_INDEX);
+       outb_p(SIO_PM_DEV, SIO_DATA);   /* Talk to GPIO regs. */
+
+       outb_p(SIO_DEV_MSB, SIO_INDEX);
+       outb_p(SIO_PM_MSB, SIO_DATA);   /* MSB of PM base address */
+
+       outb_p(SIO_DEV_LSB, SIO_INDEX);
+       outb_p(SIO_PM_LSB, SIO_DATA);   /* LSB of PM base address */
+
+       outb_p(SIO_DEV_ENB, SIO_INDEX);
+       outb_p(1, SIO_DATA);            /* Enable PM registers. */
+
+       /*
+        * Now, write the PM register which enables the GPIO registers.
+        */
+       outb_p(SIO_PM_FER2, SIO_PM_INDEX);
+       outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
+
+       /*
+        * Now, initialize the GPIO registers.
+        * We want them all to be inputs which is the
+        * power on default, so let's leave them alone.
+        * So, let's just read the board rev!
+        */
+       raw = inb_p(SIO_GP_DATA1);
+       raw &= 0x7f;    /* 7 bits of valid board revision ID. */
+
+       if (visws_board_type == VISWS_320) {
+               if (raw < 0x6) {
+                       visws_board_rev = 4;
+               } else if (raw < 0xc) {
+                       visws_board_rev = 5;
+               } else {
+                       visws_board_rev = 6;
+               }
+       } else if (visws_board_type == VISWS_540) {
+                       visws_board_rev = 2;
+               } else {
+                       visws_board_rev = raw;
+               }
+
+       printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
+              (visws_board_type == VISWS_320 ? "320" :
+              (visws_board_type == VISWS_540 ? "540" :
+               "unknown")), visws_board_rev);
+}
+
+#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
+#define BCD (LI_INTB | LI_INTC | LI_INTD)
+#define ALLDEVS (A01234 | BCD)
+
+static __init void lithium_init(void)
+{
+       set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
+       set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
+
+       if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
+           (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
+               printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
+/*             panic("This machine is not SGI Visual Workstation 320/540"); */
+       }
+
+       if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
+           (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
+               printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
+/*             panic("This machine is not SGI Visual Workstation 320/540"); */
+       }
+
+       li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
+       li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
+}
+
+static __init void cobalt_init(void)
+{
+       /*
+        * On normal SMP PC this is used only with SMP, but we have to
+        * use it and set it up here to start the Cobalt clock
+        */
+       set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
+       setup_local_APIC();
+       printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
+               (unsigned int)apic_read(APIC_LVR),
+               (unsigned int)apic_read(APIC_ID));
+
+       set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
+       set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
+       printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
+               co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
+
+       /* Enable Cobalt APIC being careful to NOT change the ID! */
+       co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
+
+       printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
+               co_apic_read(CO_APIC_ID));
+}
+
+int __init visws_trap_init_quirk(void)
+{
+       lithium_init();
+       cobalt_init();
+
+       return 1;
+}
+
+/*
+ * IRQ controller / APIC support:
+ */
+
+static DEFINE_SPINLOCK(cobalt_lock);
+
+/*
+ * Set the given Cobalt APIC Redirection Table entry to point
+ * to the given IDT vector/index.
+ */
+static inline void co_apic_set(int entry, int irq)
+{
+       co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
+       co_apic_write(CO_APIC_HI(entry), 0);
+}
+
+/*
+ * Cobalt (IO)-APIC functions to handle PCI devices.
+ */
+static inline int co_apic_ide0_hack(void)
+{
+       extern char visws_board_type;
+       extern char visws_board_rev;
+
+       if (visws_board_type == VISWS_320 && visws_board_rev == 5)
+               return 5;
+       return CO_APIC_IDE0;
+}
+
+static int is_co_apic(unsigned int irq)
+{
+       if (IS_CO_APIC(irq))
+               return CO_APIC(irq);
+
+       switch (irq) {
+               case 0: return CO_APIC_CPU;
+               case CO_IRQ_IDE0: return co_apic_ide0_hack();
+               case CO_IRQ_IDE1: return CO_APIC_IDE1;
+               default: return -1;
+       }
+}
+
+
+/*
+ * This is the SGI Cobalt (IO-)APIC:
+ */
+
+static void enable_cobalt_irq(unsigned int irq)
+{
+       co_apic_set(is_co_apic(irq), irq);
+}
+
+static void disable_cobalt_irq(unsigned int irq)
+{
+       int entry = is_co_apic(irq);
+
+       co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
+       co_apic_read(CO_APIC_LO(entry));
+}
+
+/*
+ * "irq" really just serves to identify the device.  Here is where we
+ * map this to the Cobalt APIC entry where it's physically wired.
+ * This is called via request_irq -> setup_irq -> irq_desc->startup()
+ */
+static unsigned int startup_cobalt_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cobalt_lock, flags);
+       if ((irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING)))
+               irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING);
+       enable_cobalt_irq(irq);
+       spin_unlock_irqrestore(&cobalt_lock, flags);
+       return 0;
+}
+
+static void ack_cobalt_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cobalt_lock, flags);
+       disable_cobalt_irq(irq);
+       apic_write(APIC_EOI, APIC_EIO_ACK);
+       spin_unlock_irqrestore(&cobalt_lock, flags);
+}
+
+static void end_cobalt_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cobalt_lock, flags);
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               enable_cobalt_irq(irq);
+       spin_unlock_irqrestore(&cobalt_lock, flags);
+}
+
+static struct irq_chip cobalt_irq_type = {
+       .typename =     "Cobalt-APIC",
+       .startup =      startup_cobalt_irq,
+       .shutdown =     disable_cobalt_irq,
+       .enable =       enable_cobalt_irq,
+       .disable =      disable_cobalt_irq,
+       .ack =          ack_cobalt_irq,
+       .end =          end_cobalt_irq,
+};
+
+
+/*
+ * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
+ * -- not the manner expected by the code in i8259.c.
+ *
+ * there is a 'master' physical interrupt source that gets sent to
+ * the CPU. But in the chipset there are various 'virtual' interrupts
+ * waiting to be handled. We represent this to Linux through a 'master'
+ * interrupt controller type, and through a special virtual interrupt-
+ * controller. Device drivers only see the virtual interrupt sources.
+ */
+static unsigned int startup_piix4_master_irq(unsigned int irq)
+{
+       init_8259A(0);
+
+       return startup_cobalt_irq(irq);
+}
+
+static void end_piix4_master_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cobalt_lock, flags);
+       enable_cobalt_irq(irq);
+       spin_unlock_irqrestore(&cobalt_lock, flags);
+}
+
+static struct irq_chip piix4_master_irq_type = {
+       .typename =     "PIIX4-master",
+       .startup =      startup_piix4_master_irq,
+       .ack =          ack_cobalt_irq,
+       .end =          end_piix4_master_irq,
+};
+
+
+static struct irq_chip piix4_virtual_irq_type = {
+       .typename =     "PIIX4-virtual",
+       .shutdown =     disable_8259A_irq,
+       .enable =       enable_8259A_irq,
+       .disable =      disable_8259A_irq,
+};
+
+
+/*
+ * PIIX4-8259 master/virtual functions to handle interrupt requests
+ * from legacy devices: floppy, parallel, serial, rtc.
+ *
+ * None of these get Cobalt APIC entries, neither do they have IDT
+ * entries. These interrupts are purely virtual and distributed from
+ * the 'master' interrupt source: CO_IRQ_8259.
+ *
+ * When the 8259 interrupts its handler figures out which of these
+ * devices is interrupting and dispatches to its handler.
+ *
+ * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
+ * enable_irq gets the right irq. This 'master' irq is never directly
+ * manipulated by any driver.
+ */
+static irqreturn_t piix4_master_intr(int irq, void *dev_id)
+{
+       int realirq;
+       irq_desc_t *desc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&i8259A_lock, flags);
+
+       /* Find out what's interrupting in the PIIX4 master 8259 */
+       outb(0x0c, 0x20);               /* OCW3 Poll command */
+       realirq = inb(0x20);
+
+       /*
+        * Bit 7 == 0 means invalid/spurious
+        */
+       if (unlikely(!(realirq & 0x80)))
+               goto out_unlock;
+
+       realirq &= 7;
+
+       if (unlikely(realirq == 2)) {
+               outb(0x0c, 0xa0);
+               realirq = inb(0xa0);
+
+               if (unlikely(!(realirq & 0x80)))
+                       goto out_unlock;
+
+               realirq = (realirq & 7) + 8;
+       }
+
+       /* mask and ack interrupt */
+       cached_irq_mask |= 1 << realirq;
+       if (unlikely(realirq > 7)) {
+               inb(0xa1);
+               outb(cached_slave_mask, 0xa1);
+               outb(0x60 + (realirq & 7), 0xa0);
+               outb(0x60 + 2, 0x20);
+       } else {
+               inb(0x21);
+               outb(cached_master_mask, 0x21);
+               outb(0x60 + realirq, 0x20);
+       }
+
+       spin_unlock_irqrestore(&i8259A_lock, flags);
+
+       desc = irq_desc + realirq;
+
+       /*
+        * handle this 'virtual interrupt' as a Cobalt one now.
+        */
+       kstat_cpu(smp_processor_id()).irqs[realirq]++;
+
+       if (likely(desc->action != NULL))
+               handle_IRQ_event(realirq, desc->action);
+
+       if (!(desc->status & IRQ_DISABLED))
+               enable_8259A_irq(realirq);
+
+       return IRQ_HANDLED;
+
+out_unlock:
+       spin_unlock_irqrestore(&i8259A_lock, flags);
+       return IRQ_NONE;
+}
+
+static struct irqaction master_action = {
+       .handler =      piix4_master_intr,
+       .name =         "PIIX4-8259",
+};
+
+static struct irqaction cascade_action = {
+       .handler =      no_action,
+       .name =         "cascade",
+};
+
+
+void init_VISWS_APIC_irqs(void)
+{
+       int i;
+
+       for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
+               irq_desc[i].status = IRQ_DISABLED;
+               irq_desc[i].action = 0;
+               irq_desc[i].depth = 1;
+
+               if (i == 0) {
+                       irq_desc[i].chip = &cobalt_irq_type;
+               }
+               else if (i == CO_IRQ_IDE0) {
+                       irq_desc[i].chip = &cobalt_irq_type;
+               }
+               else if (i == CO_IRQ_IDE1) {
+                       irq_desc[i].chip = &cobalt_irq_type;
+               }
+               else if (i == CO_IRQ_8259) {
+                       irq_desc[i].chip = &piix4_master_irq_type;
+               }
+               else if (i < CO_IRQ_APIC0) {
+                       irq_desc[i].chip = &piix4_virtual_irq_type;
+               }
+               else if (IS_CO_APIC(i)) {
+                       irq_desc[i].chip = &cobalt_irq_type;
+               }
+       }
+
+       setup_irq(CO_IRQ_8259, &master_action);
+       setup_irq(2, &cascade_action);
+}
index 956f38927aa7c5533cc41fd3c2ba0ea807ccb6dd..b15346092b7b72aa66e75621f4e31f72698ccbce 100644 (file)
@@ -151,7 +151,7 @@ static unsigned vmi_patch(u8 type, u16 clobbers, void *insns,
                                              insns, ip);
                case PARAVIRT_PATCH(pv_cpu_ops.iret):
                        return patch_internal(VMI_CALL_IRET, len, insns, ip);
-               case PARAVIRT_PATCH(pv_cpu_ops.irq_enable_syscall_ret):
+               case PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit):
                        return patch_internal(VMI_CALL_SYSEXIT, len, insns, ip);
                default:
                        break;
@@ -896,7 +896,7 @@ static inline int __init activate_vmi(void)
         * the backend.  They are performance critical anyway, so requiring
         * a patch is not a big problem.
         */
-       pv_cpu_ops.irq_enable_syscall_ret = (void *)0xfeedbab0;
+       pv_cpu_ops.irq_enable_sysexit = (void *)0xfeedbab0;
        pv_cpu_ops.iret = (void *)0xbadbab0;
 
 #ifdef CONFIG_SMP
@@ -932,7 +932,7 @@ static inline int __init activate_vmi(void)
                pv_apic_ops.setup_secondary_clock = vmi_time_ap_init;
 #endif
                pv_time_ops.sched_clock = vmi_sched_clock;
-               pv_time_ops.get_cpu_khz = vmi_cpu_khz;
+               pv_time_ops.get_tsc_khz = vmi_tsc_khz;
 
                /* We have true wallclock functions; disable CMOS clock sync */
                no_sync_cmos_clock = 1;
index a2b030780aa9c1ce461384da18b20c287ac85b7c..6953859fe28965bc77a7db5955a0b3a0d143127e 100644 (file)
@@ -33,8 +33,7 @@
 #include <asm/apic.h>
 #include <asm/timer.h>
 #include <asm/i8253.h>
-
-#include <irq_vectors.h>
+#include <asm/irq_vectors.h>
 
 #define VMI_ONESHOT  (VMI_ALARM_IS_ONESHOT  | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
 #define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
@@ -70,8 +69,8 @@ unsigned long long vmi_sched_clock(void)
        return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
 }
 
-/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
-unsigned long vmi_cpu_khz(void)
+/* paravirt_ops.get_tsc_khz = vmi_tsc_khz */
+unsigned long vmi_tsc_khz(void)
 {
        unsigned long long khz;
        khz = vmi_timer_ops.get_cycle_frequency();
index ce5ed083a1e905e463486e8f05e9125d2f41d157..2674f57962756a3dbb5e609dae3d8442b7d143c3 100644 (file)
@@ -60,13 +60,6 @@ SECTIONS
 
   BUG_TABLE :text
 
-  . = ALIGN(4);
-  .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
-       __tracedata_start = .;
-       *(.tracedata)
-       __tracedata_end = .;
-  }
-
   RODATA
 
   /* writeable */
index fad3674b06a58f990cabab44bd61910f975a6682..fd246e22fe6b4706d1b4201bf41a038eb08f5a5f 100644 (file)
@@ -53,13 +53,6 @@ SECTIONS
 
   RODATA
 
-  . = ALIGN(4);
-  .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
-       __tracedata_start = .;
-       *(.tracedata)
-       __tracedata_end = .;
-  }
-
   . = ALIGN(PAGE_SIZE);                /* Align data segment to page size boundary */
                                /* Data */
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -177,6 +170,7 @@ SECTIONS
        *(.con_initcall.init)
   }
   __con_initcall_end = .;
+  . = ALIGN(16);
   __x86cpuvendor_start = .;
   .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
        *(.x86cpuvendor.init)
index ba8c0b75ab0ae8c4fbbaba61c4afd6637cf4bd4a..0c029e8959c7f7221d4687b8465812393e1faff0 100644 (file)
 #include <linux/init.h>
 #include <linux/pci_ids.h>
 #include <linux/pci_regs.h>
+
+#include <asm/apic.h>
 #include <asm/pci-direct.h>
 #include <asm/io.h>
 #include <asm/paravirt.h>
+#include <asm/setup.h>
 
 #if defined CONFIG_PCI && defined CONFIG_PARAVIRT
 /*
index 61efa2f7d5645c804bba44bf524661133bc15374..c87cbd84c3e521ca92a567c751bc852a74239122 100644 (file)
@@ -249,7 +249,7 @@ static ctl_table kernel_root_table2[] = {
    doesn't violate that. We'll find out if it does. */
 static void __cpuinit vsyscall_set_cpu(int cpu)
 {
-       unsigned long *d;
+       unsigned long d;
        unsigned long node = 0;
 #ifdef CONFIG_NUMA
        node = cpu_to_node(cpu);
@@ -260,11 +260,11 @@ static void __cpuinit vsyscall_set_cpu(int cpu)
        /* Store cpu number in limit so that it can be loaded quickly
           in user space in vgetcpu.
           12 bits for the CPU and 8 bits for the node. */
-       d = (unsigned long *)(get_cpu_gdt_table(cpu) + GDT_ENTRY_PER_CPU);
-       *d = 0x0f40000000000ULL;
-       *d |= cpu;
-       *d |= (node & 0xf) << 12;
-       *d |= (node >> 4) << 48;
+       d = 0x0f40000000000ULL;
+       d |= cpu;
+       d |= (node & 0xf) << 12;
+       d |= (node >> 4) << 48;
+       write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S);
 }
 
 static void __cpuinit cpu_vsyscall_init(void *arg)
index f6c05d0410fb08717fe7f736320225bc476f0533..2f306a8268973bb531402dc7b8aa8cb14ebbd22a 100644 (file)
@@ -53,8 +53,3 @@ EXPORT_SYMBOL(init_level4_pgt);
 EXPORT_SYMBOL(load_gs_index);
 
 EXPORT_SYMBOL(_proxy_pda);
-
-#ifdef CONFIG_PARAVIRT
-/* Virtualized guests may want to use it */
-EXPORT_SYMBOL_GPL(cpu_gdt_descr);
-#endif
index 964dfa36d3679155bcbf4de5068c08ad264c867d..c70e12b1a6375bbe1eed42195cdfff320eaa07e4 100644 (file)
@@ -3,7 +3,7 @@ config LGUEST_GUEST
        select PARAVIRT
        depends on X86_32
        depends on !X86_PAE
-       depends on !(X86_VISWS || X86_VOYAGER)
+       depends on !X86_VOYAGER
        select VIRTIO
        select VIRTIO_RING
        select VIRTIO_CONSOLE
index 5c7e2fd52075be167680311b13d5e7c9d120bbe4..50dad44fb54234e2725c833fafd15b59b3db0283 100644 (file)
@@ -607,7 +607,7 @@ static unsigned long lguest_get_wallclock(void)
  * what speed it runs at, or 0 if it's unusable as a reliable clock source.
  * This matches what we want here: if we return 0 from this function, the x86
  * TSC clock will give up and not register itself. */
-static unsigned long lguest_cpu_khz(void)
+static unsigned long lguest_tsc_khz(void)
 {
        return lguest_data.tsc_khz;
 }
@@ -835,7 +835,7 @@ static __init char *lguest_memory_setup(void)
 
        /* The Linux bootloader header contains an "e820" memory map: the
         * Launcher populated the first entry with our memory limit. */
-       add_memory_region(boot_params.e820_map[0].addr,
+       e820_add_region(boot_params.e820_map[0].addr,
                          boot_params.e820_map[0].size,
                          boot_params.e820_map[0].type);
 
@@ -998,7 +998,7 @@ __init void lguest_init(void)
        /* time operations */
        pv_time_ops.get_wallclock = lguest_get_wallclock;
        pv_time_ops.time_init = lguest_time_init;
-       pv_time_ops.get_cpu_khz = lguest_cpu_khz;
+       pv_time_ops.get_tsc_khz = lguest_tsc_khz;
 
        /* Now is a good time to look at the implementations of these functions
         * before returning to the rest of lguest_init(). */
@@ -1012,6 +1012,7 @@ __init void lguest_init(void)
         * clobbered.  The Launcher places our initial pagetables somewhere at
         * the top of our physical memory, so we don't need extra space: set
         * init_pg_tables_end to the end of the kernel. */
+       init_pg_tables_start = __pa(pg0);
        init_pg_tables_end = __pa(pg0);
 
        /* Load the %fs segment register (the per-cpu segment register) with
@@ -1065,9 +1066,9 @@ __init void lguest_init(void)
        pm_power_off = lguest_power_off;
        machine_ops.restart = lguest_restart;
 
-       /* Now we're set up, call start_kernel() in init/main.c and we proceed
+       /* Now we're set up, call i386_start_kernel() in head32.c and we proceed
         * to boot as normal.  It never returns. */
-       start_kernel();
+       i386_start_kernel();
 }
 /*
  * This marks the end of stage II of our journey, The Guest.
index 76f60f52a885246ff1a8f6ce9bad2c3791d1df94..83226e0a7ce4e331aa1aac3277b1d6301bf025f8 100644 (file)
@@ -4,8 +4,8 @@
 
 obj-$(CONFIG_SMP) := msr-on-cpu.o
 
-lib-y := delay_$(BITS).o
-lib-y += usercopy_$(BITS).o getuser_$(BITS).o putuser_$(BITS).o
+lib-y := delay.o
+lib-y += usercopy_$(BITS).o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 
 ifeq ($(CONFIG_X86_32),y)
index ee1c3f635157b397e4fd70c0060b81e3ff3f34b1..dfdf428975c0cdafb64686cdcd221b3428653b68 100644 (file)
@@ -1,8 +1,10 @@
-/* Copyright 2002 Andi Kleen, SuSE Labs.
+/*
+ * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
+ * Copyright 2002 Andi Kleen, SuSE Labs.
  * Subject to the GNU Public License v2.
- * 
- * Functions to copy from and to user space.           
- */             
+ *
+ * Functions to copy from and to user space.
+ */
 
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
        .long \orig-1f  /* by default jump to orig */
 1:
        .section .altinstr_replacement,"ax"
-2:     .byte 0xe9                   /* near jump with 32bit immediate */
+2:     .byte 0xe9                      /* near jump with 32bit immediate */
        .long \alt-1b /* offset */   /* or alternatively to alt */
        .previous
        .section .altinstructions,"a"
        .align 8
        .quad  0b
        .quad  2b
-       .byte  \feature              /* when feature is set */
+       .byte  \feature                 /* when feature is set */
        .byte  5
        .byte  5
        .previous
        .endm
 
-/* Standard copy_to_user with segment limit checking */                
+       .macro ALIGN_DESTINATION
+#ifdef FIX_ALIGNMENT
+       /* check for bad alignment of destination */
+       movl %edi,%ecx
+       andl $7,%ecx
+       jz 102f                         /* already aligned */
+       subl $8,%ecx
+       negl %ecx
+       subl %ecx,%edx
+100:   movb (%rsi),%al
+101:   movb %al,(%rdi)
+       incq %rsi
+       incq %rdi
+       decl %ecx
+       jnz 100b
+102:
+       .section .fixup,"ax"
+103:   addl %r8d,%edx                  /* ecx is zerorest also */
+       jmp copy_user_handle_tail
+       .previous
+
+       .section __ex_table,"a"
+       .align 8
+       .quad 100b,103b
+       .quad 101b,103b
+       .previous
+#endif
+       .endm
+
+/* Standard copy_to_user with segment limit checking */
 ENTRY(copy_to_user)
        CFI_STARTPROC
        GET_THREAD_INFO(%rax)
        movq %rdi,%rcx
        addq %rdx,%rcx
-       jc  bad_to_user
-       cmpq threadinfo_addr_limit(%rax),%rcx
+       jc bad_to_user
+       cmpq TI_addr_limit(%rax),%rcx
        jae bad_to_user
-       xorl %eax,%eax  /* clear zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
 
-ENTRY(copy_user_generic)
+/* Standard copy_from_user with segment limit checking */
+ENTRY(copy_from_user)
        CFI_STARTPROC
-       movl $1,%ecx    /* set zero flag */
+       GET_THREAD_INFO(%rax)
+       movq %rsi,%rcx
+       addq %rdx,%rcx
+       jc bad_from_user
+       cmpq TI_addr_limit(%rax),%rcx
+       jae bad_from_user
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
+ENDPROC(copy_from_user)
 
-ENTRY(__copy_from_user_inatomic)
+ENTRY(copy_user_generic)
        CFI_STARTPROC
-       xorl %ecx,%ecx  /* clear zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
+ENDPROC(copy_user_generic)
 
-/* Standard copy_from_user with segment limit checking */      
-ENTRY(copy_from_user)
+ENTRY(__copy_from_user_inatomic)
        CFI_STARTPROC
-       GET_THREAD_INFO(%rax)
-       movq %rsi,%rcx
-       addq %rdx,%rcx
-       jc  bad_from_user
-       cmpq threadinfo_addr_limit(%rax),%rcx
-       jae  bad_from_user
-       movl $1,%ecx    /* set zero flag */
        ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
        CFI_ENDPROC
-ENDPROC(copy_from_user)
-       
+ENDPROC(__copy_from_user_inatomic)
+
        .section .fixup,"ax"
        /* must zero dest */
+ENTRY(bad_from_user)
 bad_from_user:
        CFI_STARTPROC
        movl %edx,%ecx
@@ -81,271 +111,158 @@ bad_from_user:
        rep
        stosb
 bad_to_user:
-       movl    %edx,%eax
+       movl %edx,%eax
        ret
        CFI_ENDPROC
-END(bad_from_user)
+ENDPROC(bad_from_user)
        .previous
-       
-               
+
 /*
  * copy_user_generic_unrolled - memory copy with exception handling.
- * This version is for CPUs like P4 that don't have efficient micro code for rep movsq
- *     
- * Input:      
+ * This version is for CPUs like P4 that don't have efficient micro
+ * code for rep movsq
+ *
+ * Input:
  * rdi destination
  * rsi source
  * rdx count
- * ecx zero flag -- if true zero destination on error
  *
- * Output:             
- * eax uncopied bytes or 0 if successful.
+ * Output:
+ * eax uncopied bytes or 0 if successfull.
  */
 ENTRY(copy_user_generic_unrolled)
        CFI_STARTPROC
-       pushq %rbx
-       CFI_ADJUST_CFA_OFFSET 8
-       CFI_REL_OFFSET rbx, 0
-       pushq %rcx
-       CFI_ADJUST_CFA_OFFSET 8
-       CFI_REL_OFFSET rcx, 0
-       xorl %eax,%eax          /*zero for the exception handler */
-
-#ifdef FIX_ALIGNMENT
-       /* check for bad alignment of destination */
-       movl %edi,%ecx
-       andl $7,%ecx
-       jnz  .Lbad_alignment
-.Lafter_bad_alignment:
-#endif
-
-       movq %rdx,%rcx
-
-       movl $64,%ebx
-       shrq $6,%rdx
-       decq %rdx
-       js   .Lhandle_tail
-
-       .p2align 4
-.Lloop:
-.Ls1:  movq (%rsi),%r11
-.Ls2:  movq 1*8(%rsi),%r8
-.Ls3:  movq 2*8(%rsi),%r9
-.Ls4:  movq 3*8(%rsi),%r10
-.Ld1:  movq %r11,(%rdi)
-.Ld2:  movq %r8,1*8(%rdi)
-.Ld3:  movq %r9,2*8(%rdi)
-.Ld4:  movq %r10,3*8(%rdi)
-
-.Ls5:  movq 4*8(%rsi),%r11
-.Ls6:  movq 5*8(%rsi),%r8
-.Ls7:  movq 6*8(%rsi),%r9
-.Ls8:  movq 7*8(%rsi),%r10
-.Ld5:  movq %r11,4*8(%rdi)
-.Ld6:  movq %r8,5*8(%rdi)
-.Ld7:  movq %r9,6*8(%rdi)
-.Ld8:  movq %r10,7*8(%rdi)
-
-       decq %rdx
-
+       cmpl $8,%edx
+       jb 20f          /* less then 8 bytes, go to byte copy loop */
+       ALIGN_DESTINATION
+       movl %edx,%ecx
+       andl $63,%edx
+       shrl $6,%ecx
+       jz 17f
+1:     movq (%rsi),%r8
+2:     movq 1*8(%rsi),%r9
+3:     movq 2*8(%rsi),%r10
+4:     movq 3*8(%rsi),%r11
+5:     movq %r8,(%rdi)
+6:     movq %r9,1*8(%rdi)
+7:     movq %r10,2*8(%rdi)
+8:     movq %r11,3*8(%rdi)
+9:     movq 4*8(%rsi),%r8
+10:    movq 5*8(%rsi),%r9
+11:    movq 6*8(%rsi),%r10
+12:    movq 7*8(%rsi),%r11
+13:    movq %r8,4*8(%rdi)
+14:    movq %r9,5*8(%rdi)
+15:    movq %r10,6*8(%rdi)
+16:    movq %r11,7*8(%rdi)
        leaq 64(%rsi),%rsi
        leaq 64(%rdi),%rdi
-
-       jns  .Lloop
-
-       .p2align 4
-.Lhandle_tail:
-       movl %ecx,%edx
-       andl $63,%ecx
-       shrl $3,%ecx
-       jz   .Lhandle_7
-       movl $8,%ebx
-       .p2align 4
-.Lloop_8:
-.Ls9:  movq (%rsi),%r8
-.Ld9:  movq %r8,(%rdi)
        decl %ecx
-       leaq 8(%rdi),%rdi
+       jnz 1b
+17:    movl %edx,%ecx
+       andl $7,%edx
+       shrl $3,%ecx
+       jz 20f
+18:    movq (%rsi),%r8
+19:    movq %r8,(%rdi)
        leaq 8(%rsi),%rsi
-       jnz .Lloop_8
-
-.Lhandle_7:
+       leaq 8(%rdi),%rdi
+       decl %ecx
+       jnz 18b
+20:    andl %edx,%edx
+       jz 23f
        movl %edx,%ecx
-       andl $7,%ecx
-       jz   .Lende
-       .p2align 4
-.Lloop_1:
-.Ls10: movb (%rsi),%bl
-.Ld10: movb %bl,(%rdi)
-       incq %rdi
+21:    movb (%rsi),%al
+22:    movb %al,(%rdi)
        incq %rsi
+       incq %rdi
        decl %ecx
-       jnz .Lloop_1
-
-       CFI_REMEMBER_STATE
-.Lende:
-       popq %rcx
-       CFI_ADJUST_CFA_OFFSET -8
-       CFI_RESTORE rcx
-       popq %rbx
-       CFI_ADJUST_CFA_OFFSET -8
-       CFI_RESTORE rbx
+       jnz 21b
+23:    xor %eax,%eax
        ret
-       CFI_RESTORE_STATE
 
-#ifdef FIX_ALIGNMENT
-       /* align destination */
-       .p2align 4
-.Lbad_alignment:
-       movl $8,%r9d
-       subl %ecx,%r9d
-       movl %r9d,%ecx
-       cmpq %r9,%rdx
-       jz   .Lhandle_7
-       js   .Lhandle_7
-.Lalign_1:
-.Ls11: movb (%rsi),%bl
-.Ld11: movb %bl,(%rdi)
-       incq %rsi
-       incq %rdi
-       decl %ecx
-       jnz .Lalign_1
-       subq %r9,%rdx
-       jmp .Lafter_bad_alignment
-#endif
+       .section .fixup,"ax"
+30:    shll $6,%ecx
+       addl %ecx,%edx
+       jmp 60f
+40:    lea (%rdx,%rcx,8),%rdx
+       jmp 60f
+50:    movl %ecx,%edx
+60:    jmp copy_user_handle_tail /* ecx is zerorest also */
+       .previous
 
-       /* table sorted by exception address */
        .section __ex_table,"a"
        .align 8
-       .quad .Ls1,.Ls1e        /* Ls1-Ls4 have copied zero bytes */
-       .quad .Ls2,.Ls1e
-       .quad .Ls3,.Ls1e
-       .quad .Ls4,.Ls1e
-       .quad .Ld1,.Ls1e        /* Ld1-Ld4 have copied 0-24 bytes */
-       .quad .Ld2,.Ls2e
-       .quad .Ld3,.Ls3e
-       .quad .Ld4,.Ls4e
-       .quad .Ls5,.Ls5e        /* Ls5-Ls8 have copied 32 bytes */
-       .quad .Ls6,.Ls5e
-       .quad .Ls7,.Ls5e
-       .quad .Ls8,.Ls5e
-       .quad .Ld5,.Ls5e        /* Ld5-Ld8 have copied 32-56 bytes */
-       .quad .Ld6,.Ls6e
-       .quad .Ld7,.Ls7e
-       .quad .Ld8,.Ls8e
-       .quad .Ls9,.Le_quad
-       .quad .Ld9,.Le_quad
-       .quad .Ls10,.Le_byte
-       .quad .Ld10,.Le_byte
-#ifdef FIX_ALIGNMENT
-       .quad .Ls11,.Lzero_rest
-       .quad .Ld11,.Lzero_rest
-#endif
-       .quad .Le5,.Le_zero
+       .quad 1b,30b
+       .quad 2b,30b
+       .quad 3b,30b
+       .quad 4b,30b
+       .quad 5b,30b
+       .quad 6b,30b
+       .quad 7b,30b
+       .quad 8b,30b
+       .quad 9b,30b
+       .quad 10b,30b
+       .quad 11b,30b
+       .quad 12b,30b
+       .quad 13b,30b
+       .quad 14b,30b
+       .quad 15b,30b
+       .quad 16b,30b
+       .quad 18b,40b
+       .quad 19b,40b
+       .quad 21b,50b
+       .quad 22b,50b
        .previous
-
-       /* eax: zero, ebx: 64 */
-.Ls1e:         addl $8,%eax            /* eax is bytes left uncopied within the loop (Ls1e: 64 .. Ls8e: 8) */
-.Ls2e:         addl $8,%eax
-.Ls3e:         addl $8,%eax
-.Ls4e:         addl $8,%eax
-.Ls5e:         addl $8,%eax
-.Ls6e:         addl $8,%eax
-.Ls7e:         addl $8,%eax
-.Ls8e:         addl $8,%eax
-       addq %rbx,%rdi  /* +64 */
-       subq %rax,%rdi  /* correct destination with computed offset */
-
-       shlq $6,%rdx    /* loop counter * 64 (stride length) */
-       addq %rax,%rdx  /* add offset to loopcnt */
-       andl $63,%ecx   /* remaining bytes */
-       addq %rcx,%rdx  /* add them */
-       jmp .Lzero_rest
-
-       /* exception on quad word loop in tail handling */
-       /* ecx: loopcnt/8, %edx: length, rdi: correct */
-.Le_quad:
-       shll $3,%ecx
-       andl $7,%edx
-       addl %ecx,%edx
-       /* edx: bytes to zero, rdi: dest, eax:zero */
-.Lzero_rest:
-       cmpl $0,(%rsp)
-       jz   .Le_zero
-       movq %rdx,%rcx
-.Le_byte:
-       xorl %eax,%eax
-.Le5:  rep
-       stosb
-       /* when there is another exception while zeroing the rest just return */
-.Le_zero:
-       movq %rdx,%rax
-       jmp .Lende
        CFI_ENDPROC
-ENDPROC(copy_user_generic)
+ENDPROC(copy_user_generic_unrolled)
 
-
-       /* Some CPUs run faster using the string copy instructions.
-          This is also a lot simpler. Use them when possible.
-          Patch in jmps to this code instead of copying it fully
-          to avoid unwanted aliasing in the exception tables. */
-
- /* rdi        destination
-  * rsi source
-  * rdx count
-  * ecx zero flag
-  *
-  * Output:
-  * eax uncopied bytes or 0 if successfull.
-  *
-  * Only 4GB of copy is supported. This shouldn't be a problem
-  * because the kernel normally only writes from/to page sized chunks
-  * even if user space passed a longer buffer.
-  * And more would be dangerous because both Intel and AMD have
-  * errata with rep movsq > 4GB. If someone feels the need to fix
-  * this please consider this.
-  */
+/* Some CPUs run faster using the string copy instructions.
+ * This is also a lot simpler. Use them when possible.
+ *
+ * Only 4GB of copy is supported. This shouldn't be a problem
+ * because the kernel normally only writes from/to page sized chunks
+ * even if user space passed a longer buffer.
+ * And more would be dangerous because both Intel and AMD have
+ * errata with rep movsq > 4GB. If someone feels the need to fix
+ * this please consider this.
+ *
+ * Input:
+ * rdi destination
+ * rsi source
+ * rdx count
+ *
+ * Output:
+ * eax uncopied bytes or 0 if successful.
+ */
 ENTRY(copy_user_generic_string)
        CFI_STARTPROC
-       movl %ecx,%r8d          /* save zero flag */
+       andl %edx,%edx
+       jz 4f
+       cmpl $8,%edx
+       jb 2f           /* less than 8 bytes, go to byte copy loop */
+       ALIGN_DESTINATION
        movl %edx,%ecx
        shrl $3,%ecx
-       andl $7,%edx    
-       jz   10f
-1:     rep 
-       movsq 
-       movl %edx,%ecx
-2:     rep
-       movsb
-9:     movl %ecx,%eax
-       ret
-
-       /* multiple of 8 byte */
-10:    rep
+       andl $7,%edx
+1:     rep
        movsq
-       xor %eax,%eax
+2:     movl %edx,%ecx
+3:     rep
+       movsb
+4:     xorl %eax,%eax
        ret
 
-       /* exception handling */
-3:      lea (%rdx,%rcx,8),%rax /* exception on quad loop */
-       jmp 6f
-5:     movl %ecx,%eax          /* exception on byte loop */
-       /* eax: left over bytes */
-6:     testl %r8d,%r8d         /* zero flag set? */
-       jz 7f
-       movl %eax,%ecx          /* initialize x86 loop counter */
-       push %rax
-       xorl %eax,%eax
-8:     rep
-       stosb                   /* zero the rest */
-11:    pop %rax
-7:     ret
-       CFI_ENDPROC
-END(copy_user_generic_c)
+       .section .fixup,"ax"
+11:    lea (%rdx,%rcx,8),%rcx
+12:    movl %ecx,%edx          /* ecx is zerorest also */
+       jmp copy_user_handle_tail
+       .previous
 
        .section __ex_table,"a"
-       .quad 1b,3b
-       .quad 2b,5b
-       .quad 8b,11b
-       .quad 10b,3b
+       .align 8
+       .quad 1b,11b
+       .quad 3b,12b
        .previous
+       CFI_ENDPROC
+ENDPROC(copy_user_generic_string)
index 9d3d1ab83763311b95acc0b38c87405bde3a5652..40e0e309d27e8336bca681444c36cf851d5ef286 100644 (file)
@@ -1,4 +1,6 @@
-/* Copyright 2002 Andi Kleen, SuSE Labs.
+/*
+ * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
+ * Copyright 2002 Andi Kleen, SuSE Labs.
  * Subject to the GNU Public License v2.
  *
  * Functions to copy from and to user space.
 #include <asm/current.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
-#include <asm/cpufeature.h>
-
-/*
- * copy_user_nocache - Uncached memory copy with exception handling
- * This will force destination/source out of cache for more performance.
- *
- * Input:
- * rdi destination
- * rsi source
- * rdx count
- * rcx zero flag       when 1 zero on exception
- *
- * Output:
- * eax uncopied bytes or 0 if successful.
- */
-ENTRY(__copy_user_nocache)
-       CFI_STARTPROC
-       pushq %rbx
-       CFI_ADJUST_CFA_OFFSET 8
-       CFI_REL_OFFSET rbx, 0
-       pushq %rcx              /* save zero flag */
-       CFI_ADJUST_CFA_OFFSET 8
-       CFI_REL_OFFSET rcx, 0
-
-       xorl %eax,%eax          /* zero for the exception handler */
 
+       .macro ALIGN_DESTINATION
 #ifdef FIX_ALIGNMENT
        /* check for bad alignment of destination */
        movl %edi,%ecx
        andl $7,%ecx
-       jnz  .Lbad_alignment
-.Lafter_bad_alignment:
-#endif
-
-       movq %rdx,%rcx
-
-       movl $64,%ebx
-       shrq $6,%rdx
-       decq %rdx
-       js   .Lhandle_tail
-
-       .p2align 4
-.Lloop:
-.Ls1:  movq (%rsi),%r11
-.Ls2:  movq 1*8(%rsi),%r8
-.Ls3:  movq 2*8(%rsi),%r9
-.Ls4:  movq 3*8(%rsi),%r10
-.Ld1:  movnti %r11,(%rdi)
-.Ld2:  movnti %r8,1*8(%rdi)
-.Ld3:  movnti %r9,2*8(%rdi)
-.Ld4:  movnti %r10,3*8(%rdi)
-
-.Ls5:  movq 4*8(%rsi),%r11
-.Ls6:  movq 5*8(%rsi),%r8
-.Ls7:  movq 6*8(%rsi),%r9
-.Ls8:  movq 7*8(%rsi),%r10
-.Ld5:  movnti %r11,4*8(%rdi)
-.Ld6:  movnti %r8,5*8(%rdi)
-.Ld7:  movnti %r9,6*8(%rdi)
-.Ld8:  movnti %r10,7*8(%rdi)
+       jz 102f                         /* already aligned */
+       subl $8,%ecx
+       negl %ecx
+       subl %ecx,%edx
+100:   movb (%rsi),%al
+101:   movb %al,(%rdi)
+       incq %rsi
+       incq %rdi
+       decl %ecx
+       jnz 100b
+102:
+       .section .fixup,"ax"
+103:   addl %r8d,%edx                  /* ecx is zerorest also */
+       jmp copy_user_handle_tail
+       .previous
 
-       dec  %rdx
+       .section __ex_table,"a"
+       .align 8
+       .quad 100b,103b
+       .quad 101b,103b
+       .previous
+#endif
+       .endm
 
+/*
+ * copy_user_nocache - Uncached memory copy with exception handling
+ * This will force destination/source out of cache for more performance.
+ */
+ENTRY(__copy_user_nocache)
+       CFI_STARTPROC
+       cmpl $8,%edx
+       jb 20f          /* less then 8 bytes, go to byte copy loop */
+       ALIGN_DESTINATION
+       movl %edx,%ecx
+       andl $63,%edx
+       shrl $6,%ecx
+       jz 17f
+1:     movq (%rsi),%r8
+2:     movq 1*8(%rsi),%r9
+3:     movq 2*8(%rsi),%r10
+4:     movq 3*8(%rsi),%r11
+5:     movnti %r8,(%rdi)
+6:     movnti %r9,1*8(%rdi)
+7:     movnti %r10,2*8(%rdi)
+8:     movnti %r11,3*8(%rdi)
+9:     movq 4*8(%rsi),%r8
+10:    movq 5*8(%rsi),%r9
+11:    movq 6*8(%rsi),%r10
+12:    movq 7*8(%rsi),%r11
+13:    movnti %r8,4*8(%rdi)
+14:    movnti %r9,5*8(%rdi)
+15:    movnti %r10,6*8(%rdi)
+16:    movnti %r11,7*8(%rdi)
        leaq 64(%rsi),%rsi
        leaq 64(%rdi),%rdi
-
-       jns  .Lloop
-
-       .p2align 4
-.Lhandle_tail:
-       movl %ecx,%edx
-       andl $63,%ecx
-       shrl $3,%ecx
-       jz   .Lhandle_7
-       movl $8,%ebx
-       .p2align 4
-.Lloop_8:
-.Ls9:  movq (%rsi),%r8
-.Ld9:  movnti %r8,(%rdi)
        decl %ecx
-       leaq 8(%rdi),%rdi
+       jnz 1b
+17:    movl %edx,%ecx
+       andl $7,%edx
+       shrl $3,%ecx
+       jz 20f
+18:    movq (%rsi),%r8
+19:    movnti %r8,(%rdi)
        leaq 8(%rsi),%rsi
-       jnz .Lloop_8
-
-.Lhandle_7:
+       leaq 8(%rdi),%rdi
+       decl %ecx
+       jnz 18b
+20:    andl %edx,%edx
+       jz 23f
        movl %edx,%ecx
-       andl $7,%ecx
-       jz   .Lende
-       .p2align 4
-.Lloop_1:
-.Ls10: movb (%rsi),%bl
-.Ld10: movb %bl,(%rdi)
-       incq %rdi
+21:    movb (%rsi),%al
+22:    movb %al,(%rdi)
        incq %rsi
+       incq %rdi
        decl %ecx
-       jnz .Lloop_1
-
-       CFI_REMEMBER_STATE
-.Lende:
-       popq %rcx
-       CFI_ADJUST_CFA_OFFSET -8
-       CFI_RESTORE %rcx
-       popq %rbx
-       CFI_ADJUST_CFA_OFFSET -8
-       CFI_RESTORE rbx
+       jnz 21b
+23:    xorl %eax,%eax
        sfence
        ret
-       CFI_RESTORE_STATE
 
-#ifdef FIX_ALIGNMENT
-       /* align destination */
-       .p2align 4
-.Lbad_alignment:
-       movl $8,%r9d
-       subl %ecx,%r9d
-       movl %r9d,%ecx
-       cmpq %r9,%rdx
-       jz   .Lhandle_7
-       js   .Lhandle_7
-.Lalign_1:
-.Ls11: movb (%rsi),%bl
-.Ld11: movb %bl,(%rdi)
-       incq %rsi
-       incq %rdi
-       decl %ecx
-       jnz .Lalign_1
-       subq %r9,%rdx
-       jmp .Lafter_bad_alignment
-#endif
+       .section .fixup,"ax"
+30:    shll $6,%ecx
+       addl %ecx,%edx
+       jmp 60f
+40:    lea (%rdx,%rcx,8),%rdx
+       jmp 60f
+50:    movl %ecx,%edx
+60:    sfence
+       movl %r8d,%ecx
+       jmp copy_user_handle_tail
+       .previous
 
-       /* table sorted by exception address */
        .section __ex_table,"a"
-       .align 8
-       .quad .Ls1,.Ls1e        /* .Ls[1-4] - 0 bytes copied */
-       .quad .Ls2,.Ls1e
-       .quad .Ls3,.Ls1e
-       .quad .Ls4,.Ls1e
-       .quad .Ld1,.Ls1e        /* .Ld[1-4] - 0..24 bytes coped */
-       .quad .Ld2,.Ls2e
-       .quad .Ld3,.Ls3e
-       .quad .Ld4,.Ls4e
-       .quad .Ls5,.Ls5e        /* .Ls[5-8] - 32 bytes copied */
-       .quad .Ls6,.Ls5e
-       .quad .Ls7,.Ls5e
-       .quad .Ls8,.Ls5e
-       .quad .Ld5,.Ls5e        /* .Ld[5-8] - 32..56 bytes copied */
-       .quad .Ld6,.Ls6e
-       .quad .Ld7,.Ls7e
-       .quad .Ld8,.Ls8e
-       .quad .Ls9,.Le_quad
-       .quad .Ld9,.Le_quad
-       .quad .Ls10,.Le_byte
-       .quad .Ld10,.Le_byte
-#ifdef FIX_ALIGNMENT
-       .quad .Ls11,.Lzero_rest
-       .quad .Ld11,.Lzero_rest
-#endif
-       .quad .Le5,.Le_zero
+       .quad 1b,30b
+       .quad 2b,30b
+       .quad 3b,30b
+       .quad 4b,30b
+       .quad 5b,30b
+       .quad 6b,30b
+       .quad 7b,30b
+       .quad 8b,30b
+       .quad 9b,30b
+       .quad 10b,30b
+       .quad 11b,30b
+       .quad 12b,30b
+       .quad 13b,30b
+       .quad 14b,30b
+       .quad 15b,30b
+       .quad 16b,30b
+       .quad 18b,40b
+       .quad 19b,40b
+       .quad 21b,50b
+       .quad 22b,50b
        .previous
-
-       /* eax: zero, ebx: 64 */
-.Ls1e:         addl $8,%eax    /* eax: bytes left uncopied: Ls1e: 64 .. Ls8e: 8 */
-.Ls2e:         addl $8,%eax
-.Ls3e:         addl $8,%eax
-.Ls4e:         addl $8,%eax
-.Ls5e:         addl $8,%eax
-.Ls6e:         addl $8,%eax
-.Ls7e:         addl $8,%eax
-.Ls8e:         addl $8,%eax
-       addq %rbx,%rdi  /* +64 */
-       subq %rax,%rdi  /* correct destination with computed offset */
-
-       shlq $6,%rdx    /* loop counter * 64 (stride length) */
-       addq %rax,%rdx  /* add offset to loopcnt */
-       andl $63,%ecx   /* remaining bytes */
-       addq %rcx,%rdx  /* add them */
-       jmp .Lzero_rest
-
-       /* exception on quad word loop in tail handling */
-       /* ecx: loopcnt/8, %edx: length, rdi: correct */
-.Le_quad:
-       shll $3,%ecx
-       andl $7,%edx
-       addl %ecx,%edx
-       /* edx: bytes to zero, rdi: dest, eax:zero */
-.Lzero_rest:
-       cmpl $0,(%rsp)  /* zero flag set? */
-       jz   .Le_zero
-       movq %rdx,%rcx
-.Le_byte:
-       xorl %eax,%eax
-.Le5:  rep
-       stosb
-       /* when there is another exception while zeroing the rest just return */
-.Le_zero:
-       movq %rdx,%rax
-       jmp .Lende
        CFI_ENDPROC
 ENDPROC(__copy_user_nocache)
-
-
similarity index 88%
rename from arch/x86/lib/delay_32.c
rename to arch/x86/lib/delay.c
index d710f2d167bb49505e56ed4c0e9c5cc91a52546e..f4568605d7d5c9fa7281bebfc6d8f5e2b122c8df 100644 (file)
@@ -3,6 +3,7 @@
  *
  *     Copyright (C) 1993 Linus Torvalds
  *     Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *     Copyright (C) 2008 Jiri Hladky <hladky _dot_ jiri _at_ gmail _dot_ com>
  *
  *     The __delay function must _NOT_ be inlined as its execution time
  *     depends wildly on alignment on many x86 processors. The additional
 /* simple loop based delay: */
 static void delay_loop(unsigned long loops)
 {
-       int d0;
-
-       __asm__ __volatile__(
-               "\tjmp 1f\n"
-               ".align 16\n"
-               "1:\tjmp 2f\n"
-               ".align 16\n"
-               "2:\tdecl %0\n\tjns 2b"
-               :"=&a" (d0)
-               :"0" (loops));
+       asm volatile(
+               "       test %0,%0      \n"
+               "       jz 3f           \n"
+               "       jmp 1f          \n"
+
+               ".align 16              \n"
+               "1:     jmp 2f          \n"
+
+               ".align 16              \n"
+               "2:     dec %0          \n"
+               "       jnz 2b          \n"
+               "3:     dec %0          \n"
+
+               : /* we don't need output */
+               :"a" (loops)
+       );
 }
 
 /* TSC based delay: */
@@ -91,7 +98,7 @@ void use_tsc_delay(void)
 int __devinit read_current_timer(unsigned long *timer_val)
 {
        if (delay_fn == delay_tsc) {
-               rdtscl(*timer_val);
+               rdtscll(*timer_val);
                return 0;
        }
        return -1;
@@ -101,31 +108,30 @@ void __delay(unsigned long loops)
 {
        delay_fn(loops);
 }
+EXPORT_SYMBOL(__delay);
 
 inline void __const_udelay(unsigned long xloops)
 {
        int d0;
 
        xloops *= 4;
-       __asm__("mull %0"
+       asm("mull %%edx"
                :"=d" (xloops), "=&a" (d0)
                :"1" (xloops), "0"
                (cpu_data(raw_smp_processor_id()).loops_per_jiffy * (HZ/4)));
 
        __delay(++xloops);
 }
+EXPORT_SYMBOL(__const_udelay);
 
 void __udelay(unsigned long usecs)
 {
        __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
 }
+EXPORT_SYMBOL(__udelay);
 
 void __ndelay(unsigned long nsecs)
 {
        __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
 }
-
-EXPORT_SYMBOL(__delay);
-EXPORT_SYMBOL(__const_udelay);
-EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
diff --git a/arch/x86/lib/delay_64.c b/arch/x86/lib/delay_64.c
deleted file mode 100644 (file)
index 4c441be..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *     Precise Delay Loops for x86-64
- *
- *     Copyright (C) 1993 Linus Torvalds
- *     Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- *     The __delay function must _NOT_ be inlined as its execution time
- *     depends wildly on alignment on many x86 processors. 
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timex.h>
-#include <linux/preempt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/delay.h>
-#include <asm/msr.h>
-
-#ifdef CONFIG_SMP
-#include <asm/smp.h>
-#endif
-
-int __devinit read_current_timer(unsigned long *timer_value)
-{
-       rdtscll(*timer_value);
-       return 0;
-}
-
-void __delay(unsigned long loops)
-{
-       unsigned bclock, now;
-       int cpu;
-
-       preempt_disable();
-       cpu = smp_processor_id();
-       rdtscl(bclock);
-       for (;;) {
-               rdtscl(now);
-               if ((now - bclock) >= loops)
-                       break;
-
-               /* Allow RT tasks to run */
-               preempt_enable();
-               rep_nop();
-               preempt_disable();
-
-               /*
-                * It is possible that we moved to another CPU, and
-                * since TSC's are per-cpu we need to calculate
-                * that. The delay must guarantee that we wait "at
-                * least" the amount of time. Being moved to another
-                * CPU could make the wait longer but we just need to
-                * make sure we waited long enough. Rebalance the
-                * counter for this CPU.
-                */
-               if (unlikely(cpu != smp_processor_id())) {
-                       loops -= (now - bclock);
-                       cpu = smp_processor_id();
-                       rdtscl(bclock);
-               }
-       }
-       preempt_enable();
-}
-EXPORT_SYMBOL(__delay);
-
-inline void __const_udelay(unsigned long xloops)
-{
-       __delay(((xloops * HZ *
-               cpu_data(raw_smp_processor_id()).loops_per_jiffy) >> 32) + 1);
-}
-EXPORT_SYMBOL(__const_udelay);
-
-void __udelay(unsigned long usecs)
-{
-       __const_udelay(usecs * 0x000010c7);  /* 2**32 / 1000000 (rounded up) */
-}
-EXPORT_SYMBOL(__udelay);
-
-void __ndelay(unsigned long nsecs)
-{
-       __const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
-}
-EXPORT_SYMBOL(__ndelay);
similarity index 53%
rename from arch/x86/lib/getuser_64.S
rename to arch/x86/lib/getuser.S
index 5448876261f8734b2b4367c3295dd074c8d33542..ad374003742f98534db184ebc1f019ff845141a4 100644 (file)
@@ -3,6 +3,7 @@
  *
  * (C) Copyright 1998 Linus Torvalds
  * (C) Copyright 2005 Andi Kleen
+ * (C) Copyright 2008 Glauber Costa
  *
  * These functions have a non-standard call interface
  * to make them more efficient, especially as they
 /*
  * __get_user_X
  *
- * Inputs:     %rcx contains the address.
+ * Inputs:     %[r|e]ax contains the address.
  *             The register is modified, but all changes are undone
  *             before returning because the C code doesn't know about it.
  *
- * Outputs:    %rax is error code (0 or -EFAULT)
- *             %rdx contains zero-extended value
- * 
- * %r8 is destroyed.
+ * Outputs:    %[r|e]ax is error code (0 or -EFAULT)
+ *             %[r|e]dx contains zero-extended value
+ *
  *
  * These functions should not modify any other registers,
  * as they get called from within inline assembly.
 #include <asm/errno.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
+#include <asm/asm.h>
 
        .text
 ENTRY(__get_user_1)
        CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       cmpq threadinfo_addr_limit(%r8),%rcx
+       GET_THREAD_INFO(%_ASM_DX)
+       cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
-1:     movzb (%rcx),%edx
-       xorl %eax,%eax
+1:     movzb (%_ASM_AX),%edx
+       xor %eax,%eax
        ret
        CFI_ENDPROC
 ENDPROC(__get_user_1)
 
 ENTRY(__get_user_2)
        CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       addq $1,%rcx
-       jc 20f
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae 20f
-       decq   %rcx
-2:     movzwl (%rcx),%edx
-       xorl %eax,%eax
+       add $1,%_ASM_AX
+       jc bad_get_user
+       GET_THREAD_INFO(%_ASM_DX)
+       cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+       jae bad_get_user
+2:     movzwl -1(%_ASM_AX),%edx
+       xor %eax,%eax
        ret
-20:    decq    %rcx
-       jmp     bad_get_user
        CFI_ENDPROC
 ENDPROC(__get_user_2)
 
 ENTRY(__get_user_4)
        CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       addq $3,%rcx
-       jc 30f
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae 30f
-       subq $3,%rcx
-3:     movl (%rcx),%edx
-       xorl %eax,%eax
+       add $3,%_ASM_AX
+       jc bad_get_user
+       GET_THREAD_INFO(%_ASM_DX)
+       cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+       jae bad_get_user
+3:     mov -3(%_ASM_AX),%edx
+       xor %eax,%eax
        ret
-30:    subq $3,%rcx
-       jmp bad_get_user
        CFI_ENDPROC
 ENDPROC(__get_user_4)
 
+#ifdef CONFIG_X86_64
 ENTRY(__get_user_8)
        CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       addq $7,%rcx
-       jc 40f
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae     40f
-       subq    $7,%rcx
-4:     movq (%rcx),%rdx
-       xorl %eax,%eax
+       add $7,%_ASM_AX
+       jc bad_get_user
+       GET_THREAD_INFO(%_ASM_DX)
+       cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+       jae     bad_get_user
+4:     movq -7(%_ASM_AX),%_ASM_DX
+       xor %eax,%eax
        ret
-40:    subq $7,%rcx
-       jmp bad_get_user
        CFI_ENDPROC
 ENDPROC(__get_user_8)
+#endif
 
 bad_get_user:
        CFI_STARTPROC
-       xorl %edx,%edx
-       movq $(-EFAULT),%rax
+       xor %edx,%edx
+       mov $(-EFAULT),%_ASM_AX
        ret
        CFI_ENDPROC
 END(bad_get_user)
 
 .section __ex_table,"a"
-       .quad 1b,bad_get_user
-       .quad 2b,bad_get_user
-       .quad 3b,bad_get_user
-       .quad 4b,bad_get_user
-.previous
+       _ASM_PTR 1b,bad_get_user
+       _ASM_PTR 2b,bad_get_user
+       _ASM_PTR 3b,bad_get_user
+#ifdef CONFIG_X86_64
+       _ASM_PTR 4b,bad_get_user
+#endif
diff --git a/arch/x86/lib/getuser_32.S b/arch/x86/lib/getuser_32.S
deleted file mode 100644 (file)
index 6d84b53..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * __get_user functions.
- *
- * (C) Copyright 1998 Linus Torvalds
- *
- * These functions have a non-standard call interface
- * to make them more efficient, especially as they
- * return an error value in addition to the "real"
- * return value.
- */
-#include <linux/linkage.h>
-#include <asm/dwarf2.h>
-#include <asm/thread_info.h>
-
-
-/*
- * __get_user_X
- *
- * Inputs:     %eax contains the address
- *
- * Outputs:    %eax is error code (0 or -EFAULT)
- *             %edx contains zero-extended value
- *
- * These functions should not modify any other registers,
- * as they get called from within inline assembly.
- */
-
-.text
-ENTRY(__get_user_1)
-       CFI_STARTPROC
-       GET_THREAD_INFO(%edx)
-       cmpl TI_addr_limit(%edx),%eax
-       jae bad_get_user
-1:     movzbl (%eax),%edx
-       xorl %eax,%eax
-       ret
-       CFI_ENDPROC
-ENDPROC(__get_user_1)
-
-ENTRY(__get_user_2)
-       CFI_STARTPROC
-       addl $1,%eax
-       jc bad_get_user
-       GET_THREAD_INFO(%edx)
-       cmpl TI_addr_limit(%edx),%eax
-       jae bad_get_user
-2:     movzwl -1(%eax),%edx
-       xorl %eax,%eax
-       ret
-       CFI_ENDPROC
-ENDPROC(__get_user_2)
-
-ENTRY(__get_user_4)
-       CFI_STARTPROC
-       addl $3,%eax
-       jc bad_get_user
-       GET_THREAD_INFO(%edx)
-       cmpl TI_addr_limit(%edx),%eax
-       jae bad_get_user
-3:     movl -3(%eax),%edx
-       xorl %eax,%eax
-       ret
-       CFI_ENDPROC
-ENDPROC(__get_user_4)
-
-bad_get_user:
-       CFI_STARTPROC
-       xorl %edx,%edx
-       movl $-14,%eax
-       ret
-       CFI_ENDPROC
-END(bad_get_user)
-
-.section __ex_table,"a"
-       .long 1b,bad_get_user
-       .long 2b,bad_get_user
-       .long 3b,bad_get_user
-.previous
similarity index 54%
rename from arch/x86/lib/putuser_32.S
rename to arch/x86/lib/putuser.S
index f58fba109d188a2a19d4d18255df9f1e1b52271f..36b0d15ae6e97edcc9217743a06422a6e5f5fe2e 100644 (file)
@@ -2,6 +2,8 @@
  * __put_user functions.
  *
  * (C) Copyright 2005 Linus Torvalds
+ * (C) Copyright 2005 Andi Kleen
+ * (C) Copyright 2008 Glauber Costa
  *
  * These functions have a non-standard call interface
  * to make them more efficient, especially as they
@@ -11,6 +13,8 @@
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/asm.h>
 
 
 /*
  */
 
 #define ENTER  CFI_STARTPROC ; \
-               pushl %ebx ; \
-               CFI_ADJUST_CFA_OFFSET 4 ; \
-               CFI_REL_OFFSET ebx, 0 ; \
-               GET_THREAD_INFO(%ebx)
-#define EXIT   popl %ebx ; \
-               CFI_ADJUST_CFA_OFFSET -4 ; \
-               CFI_RESTORE ebx ; \
-               ret ; \
+               GET_THREAD_INFO(%_ASM_BX)
+#define EXIT   ret ; \
                CFI_ENDPROC
 
 .text
 ENTRY(__put_user_1)
        ENTER
-       cmpl TI_addr_limit(%ebx),%ecx
+       cmp TI_addr_limit(%_ASM_BX),%_ASM_CX
        jae bad_put_user
-1:     movb %al,(%ecx)
-       xorl %eax,%eax
+1:     movb %al,(%_ASM_CX)
+       xor %eax,%eax
        EXIT
 ENDPROC(__put_user_1)
 
 ENTRY(__put_user_2)
        ENTER
-       movl TI_addr_limit(%ebx),%ebx
-       subl $1,%ebx
-       cmpl %ebx,%ecx
+       mov TI_addr_limit(%_ASM_BX),%_ASM_BX
+       sub $1,%_ASM_BX
+       cmp %_ASM_BX,%_ASM_CX
        jae bad_put_user
-2:     movw %ax,(%ecx)
-       xorl %eax,%eax
+2:     movw %ax,(%_ASM_CX)
+       xor %eax,%eax
        EXIT
 ENDPROC(__put_user_2)
 
 ENTRY(__put_user_4)
        ENTER
-       movl TI_addr_limit(%ebx),%ebx
-       subl $3,%ebx
-       cmpl %ebx,%ecx
+       mov TI_addr_limit(%_ASM_BX),%_ASM_BX
+       sub $3,%_ASM_BX
+       cmp %_ASM_BX,%_ASM_CX
        jae bad_put_user
-3:     movl %eax,(%ecx)
-       xorl %eax,%eax
+3:     movl %eax,(%_ASM_CX)
+       xor %eax,%eax
        EXIT
 ENDPROC(__put_user_4)
 
 ENTRY(__put_user_8)
        ENTER
-       movl TI_addr_limit(%ebx),%ebx
-       subl $7,%ebx
-       cmpl %ebx,%ecx
+       mov TI_addr_limit(%_ASM_BX),%_ASM_BX
+       sub $7,%_ASM_BX
+       cmp %_ASM_BX,%_ASM_CX
        jae bad_put_user
-4:     movl %eax,(%ecx)
-5:     movl %edx,4(%ecx)
-       xorl %eax,%eax
+4:     mov %_ASM_AX,(%_ASM_CX)
+#ifdef CONFIG_X86_32
+5:     movl %edx,4(%_ASM_CX)
+#endif
+       xor %eax,%eax
        EXIT
 ENDPROC(__put_user_8)
 
 bad_put_user:
-       CFI_STARTPROC simple
-       CFI_DEF_CFA esp, 2*4
-       CFI_OFFSET eip, -1*4
-       CFI_OFFSET ebx, -2*4
-       movl $-14,%eax
+       CFI_STARTPROC
+       movl $-EFAULT,%eax
        EXIT
 END(bad_put_user)
 
 .section __ex_table,"a"
-       .long 1b,bad_put_user
-       .long 2b,bad_put_user
-       .long 3b,bad_put_user
-       .long 4b,bad_put_user
-       .long 5b,bad_put_user
+       _ASM_PTR 1b,bad_put_user
+       _ASM_PTR 2b,bad_put_user
+       _ASM_PTR 3b,bad_put_user
+       _ASM_PTR 4b,bad_put_user
+#ifdef CONFIG_X86_32
+       _ASM_PTR 5b,bad_put_user
+#endif
 .previous
diff --git a/arch/x86/lib/putuser_64.S b/arch/x86/lib/putuser_64.S
deleted file mode 100644 (file)
index 4989f5a..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * __put_user functions.
- *
- * (C) Copyright 1998 Linus Torvalds
- * (C) Copyright 2005 Andi Kleen
- *
- * These functions have a non-standard call interface
- * to make them more efficient, especially as they
- * return an error value in addition to the "real"
- * return value.
- */
-
-/*
- * __put_user_X
- *
- * Inputs:     %rcx contains the address
- *             %rdx contains new value
- *
- * Outputs:    %rax is error code (0 or -EFAULT)
- *
- * %r8 is destroyed.
- *
- * These functions should not modify any other registers,
- * as they get called from within inline assembly.
- */
-
-#include <linux/linkage.h>
-#include <asm/dwarf2.h>
-#include <asm/page.h>
-#include <asm/errno.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-
-       .text
-ENTRY(__put_user_1)
-       CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae bad_put_user
-1:     movb %dl,(%rcx)
-       xorl %eax,%eax
-       ret
-       CFI_ENDPROC
-ENDPROC(__put_user_1)
-
-ENTRY(__put_user_2)
-       CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       addq $1,%rcx
-       jc 20f
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae 20f
-       decq %rcx
-2:     movw %dx,(%rcx)
-       xorl %eax,%eax
-       ret
-20:    decq %rcx
-       jmp bad_put_user
-       CFI_ENDPROC
-ENDPROC(__put_user_2)
-
-ENTRY(__put_user_4)
-       CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       addq $3,%rcx
-       jc 30f
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae 30f
-       subq $3,%rcx
-3:     movl %edx,(%rcx)
-       xorl %eax,%eax
-       ret
-30:    subq $3,%rcx
-       jmp bad_put_user
-       CFI_ENDPROC
-ENDPROC(__put_user_4)
-
-ENTRY(__put_user_8)
-       CFI_STARTPROC
-       GET_THREAD_INFO(%r8)
-       addq $7,%rcx
-       jc 40f
-       cmpq threadinfo_addr_limit(%r8),%rcx
-       jae 40f
-       subq $7,%rcx
-4:     movq %rdx,(%rcx)
-       xorl %eax,%eax
-       ret
-40:    subq $7,%rcx
-       jmp bad_put_user
-       CFI_ENDPROC
-ENDPROC(__put_user_8)
-
-bad_put_user:
-       CFI_STARTPROC
-       movq $(-EFAULT),%rax
-       ret
-       CFI_ENDPROC
-END(bad_put_user)
-
-.section __ex_table,"a"
-       .quad 1b,bad_put_user
-       .quad 2b,bad_put_user
-       .quad 3b,bad_put_user
-       .quad 4b,bad_put_user
-.previous
index 0c89d1bb02871e0324b57418d5390535c1780c2b..f4df6e7c718be506a59ef157bda9591dfb1790a6 100644 (file)
@@ -158,3 +158,26 @@ unsigned long copy_in_user(void __user *to, const void __user *from, unsigned le
 }
 EXPORT_SYMBOL(copy_in_user);
 
+/*
+ * Try to copy last bytes and clear the rest if needed.
+ * Since protection fault in copy_from/to_user is not a normal situation,
+ * it is not necessary to optimize tail handling.
+ */
+unsigned long
+copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
+{
+       char c;
+       unsigned zero_len;
+
+       for (; len; --len) {
+               if (__get_user_nocheck(c, from++, sizeof(char)))
+                       break;
+               if (__put_user_nocheck(c, to++, sizeof(char)))
+                       break;
+       }
+
+       for (c = 0, zero_len = len; zerorest && zero_len; --zero_len)
+               if (__put_user_nocheck(c, to++, sizeof(char)))
+                       break;
+       return len;
+}
index 0c28a071824c2bd0789eb9c7d929615e8ba944d1..48278fa7d3dee05eeaf2ccfa9bb8c726f6dd2f84 100644 (file)
 #include <asm/e820.h>
 #include <asm/setup.h>
 
+/*
+ * Any quirks to be performed to initialize timers/irqs/etc?
+ */
+int (*arch_time_init_quirk)(void);
+int (*arch_pre_intr_init_quirk)(void);
+int (*arch_intr_init_quirk)(void);
+int (*arch_trap_init_quirk)(void);
+
 #ifdef CONFIG_HOTPLUG_CPU
 #define DEFAULT_SEND_IPI       (1)
 #else
@@ -29,6 +37,10 @@ int no_broadcast=DEFAULT_SEND_IPI;
  **/
 void __init pre_intr_init_hook(void)
 {
+       if (arch_pre_intr_init_quirk) {
+               if (arch_pre_intr_init_quirk())
+                       return;
+       }
        init_ISA_irqs();
 }
 
@@ -52,6 +64,10 @@ static struct irqaction irq2 = {
  **/
 void __init intr_init_hook(void)
 {
+       if (arch_intr_init_quirk) {
+               if (arch_intr_init_quirk())
+                       return;
+       }
 #ifdef CONFIG_X86_LOCAL_APIC
        apic_intr_init();
 #endif
@@ -65,7 +81,7 @@ void __init intr_init_hook(void)
  *
  * Description:
  *     generally used to activate any machine specific identification
- *     routines that may be needed before setup_arch() runs.  On VISWS
+ *     routines that may be needed before setup_arch() runs.  On Voyager
  *     this is used to get the board revision and type.
  **/
 void __init pre_setup_arch_hook(void)
@@ -81,6 +97,10 @@ void __init pre_setup_arch_hook(void)
  **/
 void __init trap_init_hook(void)
 {
+       if (arch_trap_init_quirk) {
+               if (arch_trap_init_quirk())
+                       return;
+       }
 }
 
 static struct irqaction irq0  = {
@@ -99,6 +119,16 @@ static struct irqaction irq0  = {
  **/
 void __init time_init_hook(void)
 {
+       if (arch_time_init_quirk) {
+               /*
+                * A nonzero return code does not mean failure, it means
+                * that the architecture quirk does not want any
+                * generic (timer) setup to be performed after this:
+                */
+               if (arch_time_init_quirk())
+                       return;
+       }
+
        irq0.mask = cpumask_of_cpu(0);
        setup_irq(0, &irq0);
 }
@@ -142,45 +172,3 @@ static int __init print_ipi_mode(void)
 
 late_initcall(print_ipi_mode);
 
-/**
- * machine_specific_memory_setup - Hook for machine specific memory setup.
- *
- * Description:
- *     This is included late in kernel/setup.c so that it can make
- *     use of all of the static functions.
- **/
-
-char * __init machine_specific_memory_setup(void)
-{
-       char *who;
-
-
-       who = "BIOS-e820";
-
-       /*
-        * Try to copy the BIOS-supplied E820-map.
-        *
-        * Otherwise fake a memory map; one section from 0k->640k,
-        * the next section from 1mb->appropriate_mem_k
-        */
-       sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries);
-       if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries)
-           < 0) {
-               unsigned long mem_size;
-
-               /* compare results from other methods and take the greater */
-               if (boot_params.alt_mem_k
-                   < boot_params.screen_info.ext_mem_k) {
-                       mem_size = boot_params.screen_info.ext_mem_k;
-                       who = "BIOS-88";
-               } else {
-                       mem_size = boot_params.alt_mem_k;
-                       who = "BIOS-e801";
-               }
-
-               e820.nr_map = 0;
-               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-       }
-       return who;
-}
index 69dd4da218dcbb7e332f5ec15ca144000b0c15e5..3ef8b43b62fc9e3195904e57d45fd4f2031874d4 100644 (file)
@@ -3,4 +3,3 @@
 #
 
 obj-$(CONFIG_X86_ES7000)       := es7000plat.o
-obj-$(CONFIG_X86_GENERICARCH)  := es7000plat.o
index f5d6f7d8b86ec2ed6d218a2dd0aca3e36115e841..4354ce804889920f7560361cf79c2876cf7417b9 100644 (file)
@@ -52,6 +52,8 @@ static struct mip_reg         *host_reg;
 static int                     mip_port;
 static unsigned long           mip_addr, host_addr;
 
+int es7000_plat;
+
 /*
  * GSI override for ES7000 platforms.
  */
@@ -175,53 +177,6 @@ find_unisys_acpi_oem_table(unsigned long *oem_addr)
 }
 #endif
 
-/*
- * This file also gets compiled if CONFIG_X86_GENERICARCH is set. Generic
- * arch already has got following function definitions (asm-generic/es7000.c)
- * hence no need to define these for that case.
- */
-#ifndef CONFIG_X86_GENERICARCH
-void es7000_sw_apic(void);
-void __init enable_apic_mode(void)
-{
-       es7000_sw_apic();
-       return;
-}
-
-__init int mps_oem_check(struct mp_config_table *mpc, char *oem,
-               char *productid)
-{
-       if (mpc->mpc_oemptr) {
-               struct mp_config_oemtable *oem_table =
-                       (struct mp_config_oemtable *)mpc->mpc_oemptr;
-               if (!strncmp(oem, "UNISYS", 6))
-                       return parse_unisys_oem((char *)oem_table);
-       }
-       return 0;
-}
-#ifdef CONFIG_ACPI
-/* Hook from generic ACPI tables.c */
-int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-       unsigned long oem_addr;
-       if (!find_unisys_acpi_oem_table(&oem_addr)) {
-               if (es7000_check_dsdt())
-                       return parse_unisys_oem((char *)oem_addr);
-               else {
-                       setup_unisys();
-                       return 1;
-               }
-       }
-       return 0;
-}
-#else
-int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-       return 0;
-}
-#endif
-#endif /* COFIG_X86_GENERICARCH */
-
 static void
 es7000_spin(int n)
 {
index 19d6d407737b51dbb76ac08be1f83afab194f6ba..0dbd7803a1d5e4199f6d1c84676296247428a2d3 100644 (file)
@@ -2,7 +2,11 @@
 # Makefile for the generic architecture
 #
 
-EXTRA_CFLAGS   := -Iarch/x86/kernel
+EXTRA_CFLAGS                   := -Iarch/x86/kernel
 
-obj-y          := probe.o summit.o bigsmp.o es7000.o default.o 
-obj-y          += ../../x86/mach-es7000/
+obj-y                          := probe.o default.o
+obj-$(CONFIG_X86_NUMAQ)                += numaq.o
+obj-$(CONFIG_X86_SUMMIT)       += summit.o
+obj-$(CONFIG_X86_BIGSMP)       += bigsmp.o
+obj-$(CONFIG_X86_ES7000)       += es7000.o
+obj-$(CONFIG_X86_ES7000)       += ../../x86/mach-es7000/
index 95fc463056d0dc92345aaee6cbd0b5ef148add51..59d7717145590b4f70f7e75daad74bff953d8b3a 100644 (file)
@@ -23,10 +23,8 @@ static int dmi_bigsmp; /* can be set by dmi scanners */
 
 static int hp_ht_bigsmp(const struct dmi_system_id *d)
 {
-#ifdef CONFIG_X86_GENERICARCH
        printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
        dmi_bigsmp = 1;
-#endif
        return 0;
 }
 
@@ -48,7 +46,7 @@ static const struct dmi_system_id bigsmp_dmi_table[] = {
 static int probe_bigsmp(void)
 {
        if (def_to_bigsmp)
-       dmi_bigsmp = 1;
+               dmi_bigsmp = 1;
        else
                dmi_check_system(bigsmp_dmi_table);
        return dmi_bigsmp;
diff --git a/arch/x86/mach-generic/numaq.c b/arch/x86/mach-generic/numaq.c
new file mode 100644 (file)
index 0000000..8091e68
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * APIC driver for the IBM NUMAQ chipset.
+ */
+#define APIC_DEFINITION 1
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/smp.h>
+#include <asm/mpspec.h>
+#include <asm/genapic.h>
+#include <asm/fixmap.h>
+#include <asm/apicdef.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/mach-numaq/mach_apic.h>
+#include <asm/mach-numaq/mach_apicdef.h>
+#include <asm/mach-numaq/mach_ipi.h>
+#include <asm/mach-numaq/mach_mpparse.h>
+#include <asm/mach-numaq/mach_wakecpu.h>
+#include <asm/numaq.h>
+
+static int mps_oem_check(struct mp_config_table *mpc, char *oem,
+               char *productid)
+{
+       numaq_mps_oem_check(mpc, oem, productid);
+       return found_numaq;
+}
+
+static int probe_numaq(void)
+{
+       /* already know from get_memcfg_numaq() */
+       return found_numaq;
+}
+
+/* Hook from generic ACPI tables.c */
+static int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+       return 0;
+}
+
+struct genapic apic_numaq = APIC_INIT("NUMAQ", probe_numaq);
index c5ae751b994a317c32f086d59c2cf33f120b402e..5a7e4619e1c47589fc6745d5843c7ef743170318 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/apicdef.h>
 #include <asm/genapic.h>
 
+extern struct genapic apic_numaq;
 extern struct genapic apic_summit;
 extern struct genapic apic_bigsmp;
 extern struct genapic apic_es7000;
@@ -24,9 +25,18 @@ extern struct genapic apic_default;
 struct genapic *genapic = &apic_default;
 
 static struct genapic *apic_probe[] __initdata = {
+#ifdef CONFIG_X86_NUMAQ
+       &apic_numaq,
+#endif
+#ifdef CONFIG_X86_SUMMIT
        &apic_summit,
+#endif
+#ifdef CONFIG_X86_BIGSMP
        &apic_bigsmp,
+#endif
+#ifdef CONFIG_X86_ES7000
        &apic_es7000,
+#endif
        &apic_default,  /* must be last */
        NULL,
 };
@@ -54,6 +64,7 @@ early_param("apic", parse_apic);
 
 void __init generic_bigsmp_probe(void)
 {
+#ifdef CONFIG_X86_BIGSMP
        /*
         * This routine is used to switch to bigsmp mode when
         * - There is no apic= option specified by the user
@@ -67,6 +78,7 @@ void __init generic_bigsmp_probe(void)
                        printk(KERN_INFO "Overriding APIC driver with %s\n",
                               genapic->name);
                }
+#endif
 }
 
 void __init generic_apic_probe(void)
@@ -88,7 +100,8 @@ void __init generic_apic_probe(void)
 
 /* These functions can switch the APIC even after the initial ->probe() */
 
-int __init mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid)
+int __init mps_oem_check(struct mp_config_table *mpc, char *oem,
+                                char *productid)
 {
        int i;
        for (i = 0; apic_probe[i]; ++i) {
diff --git a/arch/x86/mach-visws/Makefile b/arch/x86/mach-visws/Makefile
deleted file mode 100644 (file)
index 835fd96..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-obj-y                          := setup.o traps.o reboot.o
-
-obj-$(CONFIG_X86_VISWS_APIC)   += visws_apic.o
-obj-$(CONFIG_X86_LOCAL_APIC)   += mpparse.o
diff --git a/arch/x86/mach-visws/mpparse.c b/arch/x86/mach-visws/mpparse.c
deleted file mode 100644 (file)
index 57484e9..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/smp.h>
-#include <asm/io.h>
-
-#include "cobalt.h"
-#include "mach_apic.h"
-
-/* Have we found an MP table */
-int smp_found_config;
-
-int pic_mode;
-
-extern unsigned int __cpuinitdata maxcpus;
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesn't have a BIOS(-configuration table).
- * No problem for Linux.
- */
-
-static void __init MP_processor_info (struct mpc_config_processor *m)
-{
-       int ver, logical_apicid;
-       physid_mask_t apic_cpus;
-
-       if (!(m->mpc_cpuflag & CPU_ENABLED))
-               return;
-
-       logical_apicid = m->mpc_apicid;
-       printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
-              m->mpc_cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
-              m->mpc_apicid,
-              (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
-              (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
-              m->mpc_apicver);
-
-       if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
-               boot_cpu_physical_apicid = m->mpc_apicid;
-
-       ver = m->mpc_apicver;
-       if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
-               printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
-                       m->mpc_apicid, MAX_APICS);
-               return;
-       }
-
-       apic_cpus = apicid_to_cpu_present(m->mpc_apicid);
-       physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
-       /*
-        * Validate version
-        */
-       if (ver == 0x0) {
-               printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
-                       "fixing up to 0x10. (tell your hw vendor)\n",
-                       m->mpc_apicid);
-               ver = 0x10;
-       }
-       apic_version[m->mpc_apicid] = ver;
-}
-
-void __init find_smp_config(void)
-{
-       struct mpc_config_processor *mp = phys_to_virt(CO_CPU_TAB_PHYS);
-       unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
-
-       if (ncpus > CO_CPU_MAX) {
-               printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
-                       ncpus, mp);
-
-               ncpus = CO_CPU_MAX;
-       }
-
-       if (ncpus > maxcpus)
-               ncpus = maxcpus;
-
-       smp_found_config = 1;
-       while (ncpus--)
-               MP_processor_info(mp++);
-
-       mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-}
-
-void __init get_smp_config (void)
-{
-}
diff --git a/arch/x86/mach-visws/reboot.c b/arch/x86/mach-visws/reboot.c
deleted file mode 100644 (file)
index 99332ab..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include "piix4.h"
-
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-void machine_shutdown(void)
-{
-#ifdef CONFIG_SMP
-       smp_send_stop();
-#endif
-}
-
-void machine_emergency_restart(void)
-{
-       /*
-        * Visual Workstations restart after this
-        * register is poked on the PIIX4
-        */
-       outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
-}
-
-void machine_restart(char * __unused)
-{
-       machine_shutdown();
-       machine_emergency_restart();
-}
-
-void machine_power_off(void)
-{
-       unsigned short pm_status;
-       extern unsigned int pci_bus0;
-
-       while ((pm_status = inw(PMSTS_PORT)) & 0x100)
-               outw(pm_status, PMSTS_PORT);
-
-       outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
-
-       mdelay(10);
-
-#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
-       (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
-
-       outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8);
-       outl(PIIX_SPECIAL_STOP, 0xCFC);
-}
-
-void machine_halt(void)
-{
-}
-
diff --git a/arch/x86/mach-visws/setup.c b/arch/x86/mach-visws/setup.c
deleted file mode 100644 (file)
index de4c9db..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  Unmaintained SGI Visual Workstation support.
- *  Split out from setup.c by davej@suse.de
- */
-
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include <asm/fixmap.h>
-#include <asm/arch_hooks.h>
-#include <asm/io.h>
-#include <asm/e820.h>
-#include <asm/setup.h>
-#include "cobalt.h"
-#include "piix4.h"
-
-int no_broadcast;
-
-char visws_board_type = -1;
-char visws_board_rev = -1;
-
-void __init visws_get_board_type_and_rev(void)
-{
-       int raw;
-
-       visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
-                                                        >> PIIX_GPI_BD_SHIFT;
-       /*
-        * Get Board rev.
-        * First, we have to initialize the 307 part to allow us access
-        * to the GPIO registers.  Let's map them at 0x0fc0 which is right
-        * after the PIIX4 PM section.
-        */
-       outb_p(SIO_DEV_SEL, SIO_INDEX);
-       outb_p(SIO_GP_DEV, SIO_DATA);   /* Talk to GPIO regs. */
-
-       outb_p(SIO_DEV_MSB, SIO_INDEX);
-       outb_p(SIO_GP_MSB, SIO_DATA);   /* MSB of GPIO base address */
-
-       outb_p(SIO_DEV_LSB, SIO_INDEX);
-       outb_p(SIO_GP_LSB, SIO_DATA);   /* LSB of GPIO base address */
-
-       outb_p(SIO_DEV_ENB, SIO_INDEX);
-       outb_p(1, SIO_DATA);            /* Enable GPIO registers. */
-
-       /*
-        * Now, we have to map the power management section to write
-        * a bit which enables access to the GPIO registers.
-        * What lunatic came up with this shit?
-        */
-       outb_p(SIO_DEV_SEL, SIO_INDEX);
-       outb_p(SIO_PM_DEV, SIO_DATA);   /* Talk to GPIO regs. */
-
-       outb_p(SIO_DEV_MSB, SIO_INDEX);
-       outb_p(SIO_PM_MSB, SIO_DATA);   /* MSB of PM base address */
-
-       outb_p(SIO_DEV_LSB, SIO_INDEX);
-       outb_p(SIO_PM_LSB, SIO_DATA);   /* LSB of PM base address */
-
-       outb_p(SIO_DEV_ENB, SIO_INDEX);
-       outb_p(1, SIO_DATA);            /* Enable PM registers. */
-
-       /*
-        * Now, write the PM register which enables the GPIO registers.
-        */
-       outb_p(SIO_PM_FER2, SIO_PM_INDEX);
-       outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
-
-       /*
-        * Now, initialize the GPIO registers.
-        * We want them all to be inputs which is the
-        * power on default, so let's leave them alone.
-        * So, let's just read the board rev!
-        */
-       raw = inb_p(SIO_GP_DATA1);
-       raw &= 0x7f;    /* 7 bits of valid board revision ID. */
-
-       if (visws_board_type == VISWS_320) {
-               if (raw < 0x6) {
-                       visws_board_rev = 4;
-               } else if (raw < 0xc) {
-                       visws_board_rev = 5;
-               } else {
-                       visws_board_rev = 6;
-               }
-       } else if (visws_board_type == VISWS_540) {
-                       visws_board_rev = 2;
-               } else {
-                       visws_board_rev = raw;
-               }
-
-       printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
-              (visws_board_type == VISWS_320 ? "320" :
-              (visws_board_type == VISWS_540 ? "540" :
-               "unknown")), visws_board_rev);
-}
-
-void __init pre_intr_init_hook(void)
-{
-       init_VISWS_APIC_irqs();
-}
-
-void __init intr_init_hook(void)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-       apic_intr_init();
-#endif
-}
-
-void __init pre_setup_arch_hook()
-{
-       visws_get_board_type_and_rev();
-}
-
-static struct irqaction irq0 = {
-       .handler =      timer_interrupt,
-       .flags =        IRQF_DISABLED | IRQF_IRQPOLL,
-       .name =         "timer",
-};
-
-void __init time_init_hook(void)
-{
-       printk(KERN_INFO "Starting Cobalt Timer system clock\n");
-
-       /* Set the countdown value */
-       co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
-
-       /* Start the timer */
-       co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
-
-       /* Enable (unmask) the timer interrupt */
-       co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
-
-       /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
-       setup_irq(0, &irq0);
-}
-
-/* Hook for machine specific memory setup. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-EXPORT_SYMBOL(sgivwfb_mem_phys);
-EXPORT_SYMBOL(sgivwfb_mem_size);
-
-long long mem_size __initdata = 0;
-
-char * __init machine_specific_memory_setup(void)
-{
-       long long gfx_mem_size = 8 * MB;
-
-       mem_size = boot_params.alt_mem_k;
-
-       if (!mem_size) {
-               printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
-               mem_size = 128 * MB;
-       }
-
-       /*
-        * this hardcodes the graphics memory to 8 MB
-        * it really should be sized dynamically (or at least
-        * set as a boot param)
-        */
-       if (!sgivwfb_mem_size) {
-               printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
-               sgivwfb_mem_size = 8 * MB;
-       }
-
-       /*
-        * Trim to nearest MB
-        */
-       sgivwfb_mem_size &= ~((1 << 20) - 1);
-       sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
-       add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-       add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
-       add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
-       return "PROM";
-}
diff --git a/arch/x86/mach-visws/traps.c b/arch/x86/mach-visws/traps.c
deleted file mode 100644 (file)
index bfac6ba..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* VISWS traps */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-#include <asm/io.h>
-#include <asm/arch_hooks.h>
-#include <asm/apic.h>
-#include "cobalt.h"
-#include "lithium.h"
-
-
-#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
-#define BCD (LI_INTB | LI_INTC | LI_INTD)
-#define ALLDEVS (A01234 | BCD)
-
-static __init void lithium_init(void)
-{
-       set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
-       set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
-
-       if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
-           (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
-               printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
-               panic("This machine is not SGI Visual Workstation 320/540");
-       }
-
-       if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
-           (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
-               printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
-               panic("This machine is not SGI Visual Workstation 320/540");
-       }
-
-       li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
-       li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
-}
-
-static __init void cobalt_init(void)
-{
-       /*
-        * On normal SMP PC this is used only with SMP, but we have to
-        * use it and set it up here to start the Cobalt clock
-        */
-       set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
-       setup_local_APIC();
-       printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
-               (unsigned int)apic_read(APIC_LVR),
-               (unsigned int)apic_read(APIC_ID));
-
-       set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
-       set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
-       printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
-               co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
-
-       /* Enable Cobalt APIC being careful to NOT change the ID! */
-       co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
-
-       printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
-               co_apic_read(CO_APIC_ID));
-}
-
-void __init trap_init_hook(void)
-{
-       lithium_init();
-       cobalt_init();
-}
diff --git a/arch/x86/mach-visws/visws_apic.c b/arch/x86/mach-visws/visws_apic.c
deleted file mode 100644 (file)
index cef9cb1..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- *     Copyright (C) 1999 Bent Hagemark, Ingo Molnar
- *
- *  SGI Visual Workstation interrupt controller
- *
- *  The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
- *  which serves as the main interrupt controller in the system.  Non-legacy
- *  hardware in the system uses this controller directly.  Legacy devices
- *  are connected to the PIIX4 which in turn has its 8259(s) connected to
- *  a of the Cobalt APIC entry.
- *
- *  09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
- *
- *  25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
- */
-
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/apic.h>
-#include <asm/i8259.h>
-
-#include "cobalt.h"
-#include "irq_vectors.h"
-
-
-static DEFINE_SPINLOCK(cobalt_lock);
-
-/*
- * Set the given Cobalt APIC Redirection Table entry to point
- * to the given IDT vector/index.
- */
-static inline void co_apic_set(int entry, int irq)
-{
-       co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
-       co_apic_write(CO_APIC_HI(entry), 0);
-}
-
-/*
- * Cobalt (IO)-APIC functions to handle PCI devices.
- */
-static inline int co_apic_ide0_hack(void)
-{
-       extern char visws_board_type;
-       extern char visws_board_rev;
-
-       if (visws_board_type == VISWS_320 && visws_board_rev == 5)
-               return 5;
-       return CO_APIC_IDE0;
-}
-
-static int is_co_apic(unsigned int irq)
-{
-       if (IS_CO_APIC(irq))
-               return CO_APIC(irq);
-
-       switch (irq) {
-               case 0: return CO_APIC_CPU;
-               case CO_IRQ_IDE0: return co_apic_ide0_hack();
-               case CO_IRQ_IDE1: return CO_APIC_IDE1;
-               default: return -1;
-       }
-}
-
-
-/*
- * This is the SGI Cobalt (IO-)APIC:
- */
-
-static void enable_cobalt_irq(unsigned int irq)
-{
-       co_apic_set(is_co_apic(irq), irq);
-}
-
-static void disable_cobalt_irq(unsigned int irq)
-{
-       int entry = is_co_apic(irq);
-
-       co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
-       co_apic_read(CO_APIC_LO(entry));
-}
-
-/*
- * "irq" really just serves to identify the device.  Here is where we
- * map this to the Cobalt APIC entry where it's physically wired.
- * This is called via request_irq -> setup_irq -> irq_desc->startup()
- */
-static unsigned int startup_cobalt_irq(unsigned int irq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cobalt_lock, flags);
-       if ((irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING)))
-               irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING);
-       enable_cobalt_irq(irq);
-       spin_unlock_irqrestore(&cobalt_lock, flags);
-       return 0;
-}
-
-static void ack_cobalt_irq(unsigned int irq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cobalt_lock, flags);
-       disable_cobalt_irq(irq);
-       apic_write(APIC_EOI, APIC_EIO_ACK);
-       spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static void end_cobalt_irq(unsigned int irq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cobalt_lock, flags);
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               enable_cobalt_irq(irq);
-       spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static struct irq_chip cobalt_irq_type = {
-       .typename =     "Cobalt-APIC",
-       .startup =      startup_cobalt_irq,
-       .shutdown =     disable_cobalt_irq,
-       .enable =       enable_cobalt_irq,
-       .disable =      disable_cobalt_irq,
-       .ack =          ack_cobalt_irq,
-       .end =          end_cobalt_irq,
-};
-
-
-/*
- * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
- * -- not the manner expected by the code in i8259.c.
- *
- * there is a 'master' physical interrupt source that gets sent to
- * the CPU. But in the chipset there are various 'virtual' interrupts
- * waiting to be handled. We represent this to Linux through a 'master'
- * interrupt controller type, and through a special virtual interrupt-
- * controller. Device drivers only see the virtual interrupt sources.
- */
-static unsigned int startup_piix4_master_irq(unsigned int irq)
-{
-       init_8259A(0);
-
-       return startup_cobalt_irq(irq);
-}
-
-static void end_piix4_master_irq(unsigned int irq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cobalt_lock, flags);
-       enable_cobalt_irq(irq);
-       spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static struct irq_chip piix4_master_irq_type = {
-       .typename =     "PIIX4-master",
-       .startup =      startup_piix4_master_irq,
-       .ack =          ack_cobalt_irq,
-       .end =          end_piix4_master_irq,
-};
-
-
-static struct irq_chip piix4_virtual_irq_type = {
-       .typename =     "PIIX4-virtual",
-       .shutdown =     disable_8259A_irq,
-       .enable =       enable_8259A_irq,
-       .disable =      disable_8259A_irq,
-};
-
-
-/*
- * PIIX4-8259 master/virtual functions to handle interrupt requests
- * from legacy devices: floppy, parallel, serial, rtc.
- *
- * None of these get Cobalt APIC entries, neither do they have IDT
- * entries. These interrupts are purely virtual and distributed from
- * the 'master' interrupt source: CO_IRQ_8259.
- *
- * When the 8259 interrupts its handler figures out which of these
- * devices is interrupting and dispatches to its handler.
- *
- * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
- * enable_irq gets the right irq. This 'master' irq is never directly
- * manipulated by any driver.
- */
-static irqreturn_t piix4_master_intr(int irq, void *dev_id)
-{
-       int realirq;
-       irq_desc_t *desc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8259A_lock, flags);
-
-       /* Find out what's interrupting in the PIIX4 master 8259 */
-       outb(0x0c, 0x20);               /* OCW3 Poll command */
-       realirq = inb(0x20);
-
-       /*
-        * Bit 7 == 0 means invalid/spurious
-        */
-       if (unlikely(!(realirq & 0x80)))
-               goto out_unlock;
-
-       realirq &= 7;
-
-       if (unlikely(realirq == 2)) {
-               outb(0x0c, 0xa0);
-               realirq = inb(0xa0);
-
-               if (unlikely(!(realirq & 0x80)))
-                       goto out_unlock;
-
-               realirq = (realirq & 7) + 8;
-       }
-
-       /* mask and ack interrupt */
-       cached_irq_mask |= 1 << realirq;
-       if (unlikely(realirq > 7)) {
-               inb(0xa1);
-               outb(cached_slave_mask, 0xa1);
-               outb(0x60 + (realirq & 7), 0xa0);
-               outb(0x60 + 2, 0x20);
-       } else {
-               inb(0x21);
-               outb(cached_master_mask, 0x21);
-               outb(0x60 + realirq, 0x20);
-       }
-
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-
-       desc = irq_desc + realirq;
-
-       /*
-        * handle this 'virtual interrupt' as a Cobalt one now.
-        */
-       kstat_cpu(smp_processor_id()).irqs[realirq]++;
-
-       if (likely(desc->action != NULL))
-               handle_IRQ_event(realirq, desc->action);
-
-       if (!(desc->status & IRQ_DISABLED))
-               enable_8259A_irq(realirq);
-
-       return IRQ_HANDLED;
-
-out_unlock:
-       spin_unlock_irqrestore(&i8259A_lock, flags);
-       return IRQ_NONE;
-}
-
-static struct irqaction master_action = {
-       .handler =      piix4_master_intr,
-       .name =         "PIIX4-8259",
-};
-
-static struct irqaction cascade_action = {
-       .handler =      no_action,
-       .name =         "cascade",
-};
-
-
-void init_VISWS_APIC_irqs(void)
-{
-       int i;
-
-       for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = 0;
-               irq_desc[i].depth = 1;
-
-               if (i == 0) {
-                       irq_desc[i].chip = &cobalt_irq_type;
-               }
-               else if (i == CO_IRQ_IDE0) {
-                       irq_desc[i].chip = &cobalt_irq_type;
-               }
-               else if (i == CO_IRQ_IDE1) {
-                       irq_desc[i].chip = &cobalt_irq_type;
-               }
-               else if (i == CO_IRQ_8259) {
-                       irq_desc[i].chip = &piix4_master_irq_type;
-               }
-               else if (i < CO_IRQ_APIC0) {
-                       irq_desc[i].chip = &piix4_virtual_irq_type;
-               }
-               else if (IS_CO_APIC(i)) {
-                       irq_desc[i].chip = &cobalt_irq_type;
-               }
-       }
-
-       setup_irq(CO_IRQ_8259, &master_action);
-       setup_irq(2, &cascade_action);
-}
index 5ae5466b9eb9c3b9850fca6617e36dab2c653da7..6bbdd633864cc34f8ded68bc37d9bdde0d7e8a1f 100644 (file)
@@ -62,6 +62,7 @@ void __init time_init_hook(void)
 char *__init machine_specific_memory_setup(void)
 {
        char *who;
+       int new_nr;
 
        who = "NOT VOYAGER";
 
@@ -73,7 +74,7 @@ char *__init machine_specific_memory_setup(void)
 
                e820.nr_map = 0;
                for (i = 0; voyager_memory_detect(i, &addr, &length); i++) {
-                       add_memory_region(addr, length, E820_RAM);
+                       e820_add_region(addr, length, E820_RAM);
                }
                return who;
        } else if (voyager_level == 4) {
@@ -91,43 +92,17 @@ char *__init machine_specific_memory_setup(void)
                        tom = (boot_params.screen_info.ext_mem_k) << 10;
                }
                who = "Voyager-TOM";
-               add_memory_region(0, 0x9f000, E820_RAM);
+               e820_add_region(0, 0x9f000, E820_RAM);
                /* map from 1M to top of memory */
-               add_memory_region(1 * 1024 * 1024, tom - 1 * 1024 * 1024,
+               e820_add_region(1 * 1024 * 1024, tom - 1 * 1024 * 1024,
                                  E820_RAM);
                /* FIXME: Should check the ASICs to see if I need to
                 * take out the 8M window.  Just do it at the moment
                 * */
-               add_memory_region(8 * 1024 * 1024, 8 * 1024 * 1024,
+               e820_add_region(8 * 1024 * 1024, 8 * 1024 * 1024,
                                  E820_RESERVED);
                return who;
        }
 
-       who = "BIOS-e820";
-
-       /*
-        * Try to copy the BIOS-supplied E820-map.
-        *
-        * Otherwise fake a memory map; one section from 0k->640k,
-        * the next section from 1mb->appropriate_mem_k
-        */
-       sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries);
-       if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries)
-           < 0) {
-               unsigned long mem_size;
-
-               /* compare results from other methods and take the greater */
-               if (boot_params.alt_mem_k < boot_params.screen_info.ext_mem_k) {
-                       mem_size = boot_params.screen_info.ext_mem_k;
-                       who = "BIOS-88";
-               } else {
-                       mem_size = boot_params.alt_mem_k;
-                       who = "BIOS-e801";
-               }
-
-               e820.nr_map = 0;
-               add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-               add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-       }
-       return who;
+       return default_machine_specific_memory_setup();
 }
index 8acbf0cdf1a5fb8eb4d75e1d57905104b23cce14..8dedd01e909fe4efeb2ff1501518856b23b6e967 100644 (file)
@@ -59,11 +59,6 @@ __u32 voyager_quad_processors = 0;
  * activity count.  Finally exported by i386_ksyms.c */
 static int voyager_extended_cpus = 1;
 
-/* Have we found an SMP box - used by time.c to do the profiling
-   interrupt for timeslicing; do not set to 1 until the per CPU timer
-   interrupt is active */
-int smp_found_config = 0;
-
 /* Used for the invalidate map that's also checked in the spinlock */
 static volatile unsigned long smp_invalidate_needed;
 
@@ -1137,15 +1132,6 @@ void flush_tlb_all(void)
        on_each_cpu(do_flush_tlb_all, 0, 1, 1);
 }
 
-/* used to set up the trampoline for other CPUs when the memory manager
- * is sorted out */
-void __init smp_alloc_memory(void)
-{
-       trampoline_base = alloc_bootmem_low_pages(PAGE_SIZE);
-       if (__pa(trampoline_base) >= 0x93000)
-               BUG();
-}
-
 /* send a reschedule CPI to one CPU by physical CPU number*/
 static void voyager_smp_send_reschedule(int cpu)
 {
index 04869e64b18efdd8e87a7f7b2de7995cfe2a5f9b..00548354912f41b4a2268dc7a10cbbeaa737798d 100644 (file)
@@ -16,8 +16,8 @@
 #include "reg_constant.h"
 #include "control_w.h"
 
-#define MAKE_REG(s,e,l,h) { l, h, \
-                            ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+#define MAKE_REG(s, e, l, h) { l, h, \
+               ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
 
 FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
 #if 0
@@ -40,7 +40,7 @@ FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
 FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
 
 /* Only the sign and significand (and tag) are used in internal NaNs */
-/* The 80486 never generates one of these 
+/* The 80486 never generates one of these
 FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000);
  */
 /* This is the real indefinite QNaN */
@@ -49,7 +49,7 @@ FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
 /* Only the sign (and tag) is used in internal infinities */
 FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
 
-static void fld_const(FPU_REG const *c, int adj, u_char tag)
+static void fld_const(FPU_REG const * c, int adj, u_char tag)
 {
        FPU_REG *st_new_ptr;
 
index b7b3e4c7cfc9c4cd35e953ba75d64ad7cde484f5..c107641cd39bfadb4969b6b86183fe666034616e 100644 (file)
@@ -13,5 +13,6 @@ obj-$(CONFIG_NUMA)            += discontig_32.o
 else
 obj-$(CONFIG_NUMA)             += numa_64.o
 obj-$(CONFIG_K8_NUMA)          += k8topology_64.o
-obj-$(CONFIG_ACPI_NUMA)                += srat_64.o
 endif
+obj-$(CONFIG_ACPI_NUMA)                += srat_$(BITS).o
+
index 914ccf983687dd276b8cc5827d4430cf093fd822..5dfef9fa061a653669c79bdd69382169dc68561c 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/setup.h>
 #include <asm/mmzone.h>
 #include <asm/bios_ebda.h>
+#include <asm/proto.h>
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
@@ -59,14 +60,14 @@ unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
 /*
  * 4) physnode_map     - the mapping between a pfn and owning node
  * physnode_map keeps track of the physical memory layout of a generic
- * numa node on a 256Mb break (each element of the array will
- * represent 256Mb of memory and will be marked by the node id.  so,
+ * numa node on a 64Mb break (each element of the array will
+ * represent 64Mb of memory and will be marked by the node id.  so,
  * if the first gig is on node 0, and the second gig is on node 1
  * physnode_map will contain:
  *
- *     physnode_map[0-3] = 0;
- *     physnode_map[4-7] = 1;
- *     physnode_map[8- ] = -1;
+ *     physnode_map[0-15] = 0;
+ *     physnode_map[16-31] = 1;
+ *     physnode_map[32- ] = -1;
  */
 s8 physnode_map[MAX_ELEMENTS] __read_mostly = { [0 ... (MAX_ELEMENTS - 1)] = -1};
 EXPORT_SYMBOL(physnode_map);
@@ -75,15 +76,15 @@ void memory_present(int nid, unsigned long start, unsigned long end)
 {
        unsigned long pfn;
 
-       printk(KERN_INFO "Node: %d, start_pfn: %ld, end_pfn: %ld\n",
+       printk(KERN_INFO "Node: %d, start_pfn: %lx, end_pfn: %lx\n",
                        nid, start, end);
        printk(KERN_DEBUG "  Setting physnode_map array to node %d for pfns:\n", nid);
        printk(KERN_DEBUG "  ");
        for (pfn = start; pfn < end; pfn += PAGES_PER_ELEMENT) {
                physnode_map[pfn / PAGES_PER_ELEMENT] = nid;
-               printk("%ld ", pfn);
+               printk(KERN_CONT "%lx ", pfn);
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
 }
 
 unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
@@ -99,7 +100,6 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
 #endif
 
 extern unsigned long find_max_low_pfn(void);
-extern void add_one_highpage_init(struct page *, int, int);
 extern unsigned long highend_pfn, highstart_pfn;
 
 #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
@@ -117,13 +117,13 @@ static unsigned long kva_pages;
  */
 int __init get_memcfg_numa_flat(void)
 {
-       printk("NUMA - single node, flat memory mode\n");
+       printk(KERN_DEBUG "NUMA - single node, flat memory mode\n");
 
-       /* Run the memory configuration and find the top of memory. */
-       propagate_e820_map();
        node_start_pfn[0] = 0;
        node_end_pfn[0] = max_pfn;
+       e820_register_active_regions(0, 0, max_pfn);
        memory_present(0, 0, max_pfn);
+       node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
 
         /* Indicate there is one node available. */
        nodes_clear(node_online_map);
@@ -156,24 +156,32 @@ static void __init propagate_e820_map_node(int nid)
  */
 static void __init allocate_pgdat(int nid)
 {
-       if (nid && node_has_online_mem(nid))
+       char buf[16];
+
+       if (node_has_online_mem(nid) && node_remap_start_vaddr[nid])
                NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
        else {
-               NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(min_low_pfn));
-               min_low_pfn += PFN_UP(sizeof(pg_data_t));
+               unsigned long pgdat_phys;
+               pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT,
+                                max_pfn_mapped<<PAGE_SHIFT,
+                                sizeof(pg_data_t),
+                                PAGE_SIZE);
+               NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
+               memset(buf, 0, sizeof(buf));
+               sprintf(buf, "NODE_DATA %d",  nid);
+               reserve_early(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
        }
+       printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
+               nid, (unsigned long)NODE_DATA(nid));
 }
 
-#ifdef CONFIG_DISCONTIGMEM
 /*
- * In the discontig memory model, a portion of the kernel virtual area (KVA)
- * is reserved and portions of nodes are mapped using it. This is to allow
- * node-local memory to be allocated for structures that would normally require
- * ZONE_NORMAL. The memory is allocated with alloc_remap() and callers
- * should be prepared to allocate from the bootmem allocator instead. This KVA
- * mechanism is incompatible with SPARSEMEM as it makes assumptions about the
- * layout of memory that are broken if alloc_remap() succeeds for some of the
- * map and fails for others
+ * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel
+ * virtual address space (KVA) is reserved and portions of nodes are mapped
+ * using it. This is to allow node-local memory to be allocated for
+ * structures that would normally require ZONE_NORMAL. The memory is
+ * allocated with alloc_remap() and callers should be prepared to allocate
+ * from the bootmem allocator instead.
  */
 static unsigned long node_remap_start_pfn[MAX_NUMNODES];
 static void *node_remap_end_vaddr[MAX_NUMNODES];
@@ -195,15 +203,19 @@ void *alloc_remap(int nid, unsigned long size)
        return allocation;
 }
 
-void __init remap_numa_kva(void)
+static void __init remap_numa_kva(void)
 {
        void *vaddr;
        unsigned long pfn;
        int node;
 
        for_each_online_node(node) {
+               printk(KERN_DEBUG "remap_numa_kva: node %d\n", node);
                for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) {
                        vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT);
+                       printk(KERN_DEBUG "remap_numa_kva: %08lx to pfn %08lx\n",
+                               (unsigned long)vaddr,
+                               node_remap_start_pfn[node] + pfn);
                        set_pmd_pfn((ulong) vaddr, 
                                node_remap_start_pfn[node] + pfn, 
                                PAGE_KERNEL_LARGE);
@@ -215,17 +227,21 @@ static unsigned long calculate_numa_remap_pages(void)
 {
        int nid;
        unsigned long size, reserve_pages = 0;
-       unsigned long pfn;
 
        for_each_online_node(nid) {
-               unsigned old_end_pfn = node_end_pfn[nid];
+               u64 node_kva_target;
+               u64 node_kva_final;
 
                /*
                 * The acpi/srat node info can show hot-add memroy zones
                 * where memory could be added but not currently present.
                 */
+               printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
+                       nid, node_start_pfn[nid], node_end_pfn[nid]);
                if (node_start_pfn[nid] > max_pfn)
                        continue;
+               if (!node_end_pfn[nid])
+                       continue;
                if (node_end_pfn[nid] > max_pfn)
                        node_end_pfn[nid] = max_pfn;
 
@@ -237,41 +253,48 @@ static unsigned long calculate_numa_remap_pages(void)
                /* now the roundup is correct, convert to PAGE_SIZE pages */
                size = size * PTRS_PER_PTE;
 
-               /*
-                * Validate the region we are allocating only contains valid
-                * pages.
-                */
-               for (pfn = node_end_pfn[nid] - size;
-                    pfn < node_end_pfn[nid]; pfn++)
-                       if (!page_is_ram(pfn))
-                               break;
-
-               if (pfn != node_end_pfn[nid])
-                       size = 0;
+               node_kva_target = round_down(node_end_pfn[nid] - size,
+                                                PTRS_PER_PTE);
+               node_kva_target <<= PAGE_SHIFT;
+               do {
+                       node_kva_final = find_e820_area(node_kva_target,
+                                       ((u64)node_end_pfn[nid])<<PAGE_SHIFT,
+                                               ((u64)size)<<PAGE_SHIFT,
+                                               LARGE_PAGE_BYTES);
+                       node_kva_target -= LARGE_PAGE_BYTES;
+               } while (node_kva_final == -1ULL &&
+                        (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
+
+               if (node_kva_final == -1ULL)
+                       panic("Can not get kva ram\n");
 
-               printk("Reserving %ld pages of KVA for lmem_map of node %d\n",
-                               size, nid);
                node_remap_size[nid] = size;
                node_remap_offset[nid] = reserve_pages;
                reserve_pages += size;
-               printk("Shrinking node %d from %ld pages to %ld pages\n",
-                       nid, node_end_pfn[nid], node_end_pfn[nid] - size);
-
-               if (node_end_pfn[nid] & (PTRS_PER_PTE-1)) {
-                       /*
-                        * Align node_end_pfn[] and node_remap_start_pfn[] to
-                        * pmd boundary. remap_numa_kva will barf otherwise.
-                        */
-                       printk("Shrinking node %d further by %ld pages for proper alignment\n",
-                               nid, node_end_pfn[nid] & (PTRS_PER_PTE-1));
-                       size +=  node_end_pfn[nid] & (PTRS_PER_PTE-1);
-               }
+               printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of"
+                                 " node %d at %llx\n",
+                               size, nid, node_kva_final>>PAGE_SHIFT);
+
+               /*
+                *  prevent kva address below max_low_pfn want it on system
+                *  with less memory later.
+                *  layout will be: KVA address , KVA RAM
+                *
+                *  we are supposed to only record the one less then max_low_pfn
+                *  but we could have some hole in high memory, and it will only
+                *  check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
+                *  to use it as free.
+                *  So reserve_early here, hope we don't run out of that array
+                */
+               reserve_early(node_kva_final,
+                             node_kva_final+(((u64)size)<<PAGE_SHIFT),
+                             "KVA RAM");
 
-               node_end_pfn[nid] -= size;
-               node_remap_start_pfn[nid] = node_end_pfn[nid];
-               shrink_active_range(nid, old_end_pfn, node_end_pfn[nid]);
+               node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
+               remove_active_range(nid, node_remap_start_pfn[nid],
+                                        node_remap_start_pfn[nid] + size);
        }
-       printk("Reserving total of %ld pages for numa KVA remap\n",
+       printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
                        reserve_pages);
        return reserve_pages;
 }
@@ -285,37 +308,16 @@ static void init_remap_allocator(int nid)
        node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] +
                ALIGN(sizeof(pg_data_t), PAGE_SIZE);
 
-       printk ("node %d will remap to vaddr %08lx - %08lx\n", nid,
+       printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid,
                (ulong) node_remap_start_vaddr[nid],
-               (ulong) pfn_to_kaddr(highstart_pfn
-                  + node_remap_offset[nid] + node_remap_size[nid]));
-}
-#else
-void *alloc_remap(int nid, unsigned long size)
-{
-       return NULL;
-}
-
-static unsigned long calculate_numa_remap_pages(void)
-{
-       return 0;
-}
-
-static void init_remap_allocator(int nid)
-{
-}
-
-void __init remap_numa_kva(void)
-{
+               (ulong) node_remap_end_vaddr[nid]);
 }
-#endif /* CONFIG_DISCONTIGMEM */
 
-extern void setup_bootmem_allocator(void);
-unsigned long __init setup_memory(void)
+void __init initmem_init(unsigned long start_pfn,
+                                 unsigned long end_pfn)
 {
        int nid;
-       unsigned long system_start_pfn, system_max_low_pfn;
-       unsigned long wasted_pages;
+       long kva_target_pfn;
 
        /*
         * When mapping a NUMA machine we allocate the node_mem_map arrays
@@ -324,109 +326,77 @@ unsigned long __init setup_memory(void)
         * this space and use it to adjust the boundary between ZONE_NORMAL
         * and ZONE_HIGHMEM.
         */
-       get_memcfg_numa();
 
-       kva_pages = calculate_numa_remap_pages();
+       get_memcfg_numa();
 
-       /* partially used pages are not usable - thus round upwards */
-       system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end);
+       kva_pages = round_up(calculate_numa_remap_pages(), PTRS_PER_PTE);
 
-       kva_start_pfn = find_max_low_pfn() - kva_pages;
+       kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
+       do {
+               kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT,
+                                       max_low_pfn<<PAGE_SHIFT,
+                                       kva_pages<<PAGE_SHIFT,
+                                       PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
+               kva_target_pfn -= PTRS_PER_PTE;
+       } while (kva_start_pfn == -1UL && kva_target_pfn > min_low_pfn);
 
-#ifdef CONFIG_BLK_DEV_INITRD
-       /* Numa kva area is below the initrd */
-       if (initrd_start)
-               kva_start_pfn = PFN_DOWN(initrd_start - PAGE_OFFSET)
-                       - kva_pages;
-#endif
+       if (kva_start_pfn == -1UL)
+               panic("Can not get kva space\n");
 
-       /*
-        * We waste pages past at the end of the KVA for no good reason other
-        * than how it is located. This is bad.
-        */
-       wasted_pages = kva_start_pfn & (PTRS_PER_PTE-1);
-       kva_start_pfn -= wasted_pages;
-       kva_pages += wasted_pages;
-
-       system_max_low_pfn = max_low_pfn = find_max_low_pfn();
-       printk("kva_start_pfn ~ %ld find_max_low_pfn() ~ %ld\n",
+       printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
                kva_start_pfn, max_low_pfn);
-       printk("max_pfn = %ld\n", max_pfn);
+       printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
+
+       /* avoid clash with initrd */
+       reserve_early(kva_start_pfn<<PAGE_SHIFT,
+                     (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
+                    "KVA PG");
 #ifdef CONFIG_HIGHMEM
        highstart_pfn = highend_pfn = max_pfn;
-       if (max_pfn > system_max_low_pfn)
-               highstart_pfn = system_max_low_pfn;
+       if (max_pfn > max_low_pfn)
+               highstart_pfn = max_low_pfn;
        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
-       num_physpages = system_max_low_pfn;
-       high_memory = (void *) __va(system_max_low_pfn * PAGE_SIZE - 1) + 1;
+       num_physpages = max_low_pfn;
+       high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
        printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
-                       pages_to_mb(system_max_low_pfn));
-       printk("min_low_pfn = %ld, max_low_pfn = %ld, highstart_pfn = %ld\n", 
-                       min_low_pfn, max_low_pfn, highstart_pfn);
+                       pages_to_mb(max_low_pfn));
+       printk(KERN_DEBUG "max_low_pfn = %lx, highstart_pfn = %lx\n",
+                       max_low_pfn, highstart_pfn);
 
-       printk("Low memory ends at vaddr %08lx\n",
+       printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n",
                        (ulong) pfn_to_kaddr(max_low_pfn));
        for_each_online_node(nid) {
                init_remap_allocator(nid);
 
                allocate_pgdat(nid);
        }
-       printk("High memory starts at vaddr %08lx\n",
+       remap_numa_kva();
+
+       printk(KERN_DEBUG "High memory starts at vaddr %08lx\n",
                        (ulong) pfn_to_kaddr(highstart_pfn));
        for_each_online_node(nid)
                propagate_e820_map_node(nid);
 
-       memset(NODE_DATA(0), 0, sizeof(struct pglist_data));
+       for_each_online_node(nid)
+               memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
+
        NODE_DATA(0)->bdata = &node0_bdata;
        setup_bootmem_allocator();
-       return max_low_pfn;
-}
-
-void __init numa_kva_reserve(void)
-{
-       if (kva_pages)
-               reserve_bootmem(PFN_PHYS(kva_start_pfn), PFN_PHYS(kva_pages),
-                               BOOTMEM_DEFAULT);
 }
 
-void __init zone_sizes_init(void)
-{
-       int nid;
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-       max_zone_pfns[ZONE_DMA] =
-               virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
-#ifdef CONFIG_HIGHMEM
-       max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
-#endif
-
-       /* If SRAT has not registered memory, register it now */
-       if (find_max_pfn_with_active_regions() == 0) {
-               for_each_online_node(nid) {
-                       if (node_has_online_mem(nid))
-                               add_active_range(nid, node_start_pfn[nid],
-                                                       node_end_pfn[nid]);
-               }
-       }
-
-       free_area_init_nodes(max_zone_pfns);
-       return;
-}
-
-void __init set_highmem_pages_init(int bad_ppro) 
+void __init set_highmem_pages_init(void)
 {
 #ifdef CONFIG_HIGHMEM
        struct zone *zone;
-       struct page *page;
+       int nid;
 
        for_each_zone(zone) {
-               unsigned long node_pfn, zone_start_pfn, zone_end_pfn;
+               unsigned long zone_start_pfn, zone_end_pfn;
 
                if (!is_highmem(zone))
                        continue;
@@ -434,16 +404,12 @@ void __init set_highmem_pages_init(int bad_ppro)
                zone_start_pfn = zone->zone_start_pfn;
                zone_end_pfn = zone_start_pfn + zone->spanned_pages;
 
-               printk("Initializing %s for node %d (%08lx:%08lx)\n",
-                               zone->name, zone_to_nid(zone),
-                               zone_start_pfn, zone_end_pfn);
+               nid = zone_to_nid(zone);
+               printk(KERN_INFO "Initializing %s for node %d (%08lx:%08lx)\n",
+                               zone->name, nid, zone_start_pfn, zone_end_pfn);
 
-               for (node_pfn = zone_start_pfn; node_pfn < zone_end_pfn; node_pfn++) {
-                       if (!pfn_valid(node_pfn))
-                               continue;
-                       page = pfn_to_page(node_pfn);
-                       add_one_highpage_init(page, node_pfn, bad_ppro);
-               }
+               add_highpages_with_active_regions(nid, zone_start_pfn,
+                                zone_end_pfn);
        }
        totalram_pages += totalhigh_pages;
 #endif
@@ -476,3 +442,4 @@ int memory_add_physaddr_to_nid(u64 addr)
 
 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 #endif
+
index 2c24bea92c669457d50c77b7752c1954e6654f11..0bb0caed8971878152ed52d26dce836637bf82f7 100644 (file)
@@ -42,7 +42,7 @@ static struct addr_marker address_markers[] = {
        { 0, "User Space" },
 #ifdef CONFIG_X86_64
        { 0x8000000000000000UL, "Kernel Space" },
-       { 0xffff810000000000UL, "Low Kernel Mapping" },
+       { PAGE_OFFSET,          "Low Kernel Mapping" },
        { VMALLOC_START,        "vmalloc() Area" },
        { VMEMMAP_START,        "Vmemmap" },
        { __START_KERNEL_map,   "High Kernel Mapping" },
index 8bcb6f40ccb6c61b762fac7def5c26a8eb01ba4b..d0f5fce77d95b9f8afa7c0879a3e211b937365b8 100644 (file)
@@ -55,11 +55,7 @@ static inline int notify_page_fault(struct pt_regs *regs)
        int ret = 0;
 
        /* kprobe_running() needs smp_processor_id() */
-#ifdef CONFIG_X86_32
        if (!user_mode_vm(regs)) {
-#else
-       if (!user_mode(regs)) {
-#endif
                preempt_disable();
                if (kprobe_running() && kprobe_fault_handler(regs, 14))
                        ret = 1;
@@ -396,11 +392,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code,
                printk(KERN_CONT "NULL pointer dereference");
        else
                printk(KERN_CONT "paging request");
-#ifdef CONFIG_X86_32
-       printk(KERN_CONT " at %08lx\n", address);
-#else
-       printk(KERN_CONT " at %016lx\n", address);
-#endif
+       printk(KERN_CONT " at %p\n", (void *) address);
        printk(KERN_ALERT "IP:");
        printk_address(regs->ip, 1);
        dump_pagetable(address);
@@ -800,14 +792,10 @@ bad_area_nosemaphore:
                if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
                    printk_ratelimit()) {
                        printk(
-#ifdef CONFIG_X86_32
-                       "%s%s[%d]: segfault at %lx ip %08lx sp %08lx error %lx",
-#else
-                       "%s%s[%d]: segfault at %lx ip %lx sp %lx error %lx",
-#endif
+                       "%s%s[%d]: segfault at %lx ip %p sp %p error %lx",
                        task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
-                       tsk->comm, task_pid_nr(tsk), address, regs->ip,
-                       regs->sp, error_code);
+                       tsk->comm, task_pid_nr(tsk), address,
+                       (void *) regs->ip, (void *) regs->sp, error_code);
                        print_vma_addr(" in ", regs->ip);
                        printk("\n");
                }
@@ -915,14 +903,7 @@ LIST_HEAD(pgd_list);
 void vmalloc_sync_all(void)
 {
 #ifdef CONFIG_X86_32
-       /*
-        * Note that races in the updates of insync and start aren't
-        * problematic: insync can only get set bits added, and updates to
-        * start are only improving performance (without affecting correctness
-        * if undone).
-        */
-       static DECLARE_BITMAP(insync, PTRS_PER_PGD);
-       static unsigned long start = TASK_SIZE;
+       unsigned long start = VMALLOC_START & PGDIR_MASK;
        unsigned long address;
 
        if (SHARED_KERNEL_PMD)
@@ -930,56 +911,38 @@ void vmalloc_sync_all(void)
 
        BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
        for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
-               if (!test_bit(pgd_index(address), insync)) {
-                       unsigned long flags;
-                       struct page *page;
-
-                       spin_lock_irqsave(&pgd_lock, flags);
-                       list_for_each_entry(page, &pgd_list, lru) {
-                               if (!vmalloc_sync_one(page_address(page),
-                                                     address))
-                                       break;
-                       }
-                       spin_unlock_irqrestore(&pgd_lock, flags);
-                       if (!page)
-                               set_bit(pgd_index(address), insync);
+               unsigned long flags;
+               struct page *page;
+
+               spin_lock_irqsave(&pgd_lock, flags);
+               list_for_each_entry(page, &pgd_list, lru) {
+                       if (!vmalloc_sync_one(page_address(page),
+                                             address))
+                               break;
                }
-               if (address == start && test_bit(pgd_index(address), insync))
-                       start = address + PGDIR_SIZE;
+               spin_unlock_irqrestore(&pgd_lock, flags);
        }
 #else /* CONFIG_X86_64 */
-       /*
-        * Note that races in the updates of insync and start aren't
-        * problematic: insync can only get set bits added, and updates to
-        * start are only improving performance (without affecting correctness
-        * if undone).
-        */
-       static DECLARE_BITMAP(insync, PTRS_PER_PGD);
-       static unsigned long start = VMALLOC_START & PGDIR_MASK;
+       unsigned long start = VMALLOC_START & PGDIR_MASK;
        unsigned long address;
 
        for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
-               if (!test_bit(pgd_index(address), insync)) {
-                       const pgd_t *pgd_ref = pgd_offset_k(address);
-                       unsigned long flags;
-                       struct page *page;
-
-                       if (pgd_none(*pgd_ref))
-                               continue;
-                       spin_lock_irqsave(&pgd_lock, flags);
-                       list_for_each_entry(page, &pgd_list, lru) {
-                               pgd_t *pgd;
-                               pgd = (pgd_t *)page_address(page) + pgd_index(address);
-                               if (pgd_none(*pgd))
-                                       set_pgd(pgd, *pgd_ref);
-                               else
-                                       BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
-                       }
-                       spin_unlock_irqrestore(&pgd_lock, flags);
-                       set_bit(pgd_index(address), insync);
+               const pgd_t *pgd_ref = pgd_offset_k(address);
+               unsigned long flags;
+               struct page *page;
+
+               if (pgd_none(*pgd_ref))
+                       continue;
+               spin_lock_irqsave(&pgd_lock, flags);
+               list_for_each_entry(page, &pgd_list, lru) {
+                       pgd_t *pgd;
+                       pgd = (pgd_t *)page_address(page) + pgd_index(address);
+                       if (pgd_none(*pgd))
+                               set_pgd(pgd, *pgd_ref);
+                       else
+                               BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
                }
-               if (address == start)
-                       start = address + PGDIR_SIZE;
+               spin_unlock_irqrestore(&pgd_lock, flags);
        }
 #endif
 }
index ec30d10154b657a63ab07b5e25b4298c10f4aabe..029e8cffca9e11cf1794b0cad1c74029eaefa815 100644 (file)
@@ -50,6 +50,7 @@
 
 unsigned int __VMALLOC_RESERVE = 128 << 20;
 
+unsigned long max_low_pfn_mapped;
 unsigned long max_pfn_mapped;
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -57,6 +58,27 @@ unsigned long highstart_pfn, highend_pfn;
 
 static noinline int do_test_wp_bit(void);
 
+
+static unsigned long __initdata table_start;
+static unsigned long __meminitdata table_end;
+static unsigned long __meminitdata table_top;
+
+static int __initdata after_init_bootmem;
+
+static __init void *alloc_low_page(unsigned long *phys)
+{
+       unsigned long pfn = table_end++;
+       void *adr;
+
+       if (pfn >= table_top)
+               panic("alloc_low_page: ran out of memory");
+
+       adr = __va(pfn * PAGE_SIZE);
+       memset(adr, 0, PAGE_SIZE);
+       *phys  = pfn * PAGE_SIZE;
+       return adr;
+}
+
 /*
  * Creates a middle page table and puts a pointer to it in the
  * given global directory entry. This only returns the gd entry
@@ -68,9 +90,12 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
        pmd_t *pmd_table;
 
 #ifdef CONFIG_X86_PAE
+       unsigned long phys;
        if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
-               pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-
+               if (after_init_bootmem)
+                       pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+               else
+                       pmd_table = (pmd_t *)alloc_low_page(&phys);
                paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT);
                set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
                pud = pud_offset(pgd, 0);
@@ -92,12 +117,16 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
        if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
                pte_t *page_table = NULL;
 
+               if (after_init_bootmem) {
 #ifdef CONFIG_DEBUG_PAGEALLOC
-               page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
+                       page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
 #endif
-               if (!page_table) {
-                       page_table =
+                       if (!page_table)
+                               page_table =
                                (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+               } else {
+                       unsigned long phys;
+                       page_table = (pte_t *)alloc_low_page(&phys);
                }
 
                paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT);
@@ -155,38 +184,44 @@ static inline int is_kernel_text(unsigned long addr)
  * of max_low_pfn pages, by creating page tables starting from address
  * PAGE_OFFSET:
  */
-static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
+static void __init kernel_physical_mapping_init(pgd_t *pgd_base,
+                                               unsigned long start_pfn,
+                                               unsigned long end_pfn,
+                                               int use_pse)
 {
        int pgd_idx, pmd_idx, pte_ofs;
        unsigned long pfn;
        pgd_t *pgd;
        pmd_t *pmd;
        pte_t *pte;
+       unsigned pages_2m = 0, pages_4k = 0;
 
-       pgd_idx = pgd_index(PAGE_OFFSET);
-       pgd = pgd_base + pgd_idx;
-       pfn = 0;
+       if (!cpu_has_pse)
+               use_pse = 0;
 
+       pfn = start_pfn;
+       pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
+       pgd = pgd_base + pgd_idx;
        for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
                pmd = one_md_table_init(pgd);
-               if (pfn >= max_low_pfn)
-                       continue;
 
-               for (pmd_idx = 0;
-                    pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn;
+               if (pfn >= end_pfn)
+                       continue;
+#ifdef CONFIG_X86_PAE
+               pmd_idx = pmd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
+               pmd += pmd_idx;
+#else
+               pmd_idx = 0;
+#endif
+               for (; pmd_idx < PTRS_PER_PMD && pfn < end_pfn;
                     pmd++, pmd_idx++) {
                        unsigned int addr = pfn * PAGE_SIZE + PAGE_OFFSET;
 
                        /*
                         * Map with big pages if possible, otherwise
                         * create normal page tables:
-                        *
-                        * Don't use a large page for the first 2/4MB of memory
-                        * because there are often fixed size MTRRs in there
-                        * and overlapping MTRRs into large pages can cause
-                        * slowdowns.
                         */
-                       if (cpu_has_pse && !(pgd_idx == 0 && pmd_idx == 0)) {
+                       if (use_pse) {
                                unsigned int addr2;
                                pgprot_t prot = PAGE_KERNEL_LARGE;
 
@@ -197,34 +232,30 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
                                    is_kernel_text(addr2))
                                        prot = PAGE_KERNEL_LARGE_EXEC;
 
+                               pages_2m++;
                                set_pmd(pmd, pfn_pmd(pfn, prot));
 
                                pfn += PTRS_PER_PTE;
-                               max_pfn_mapped = pfn;
                                continue;
                        }
                        pte = one_page_table_init(pmd);
 
-                       for (pte_ofs = 0;
-                            pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn;
+                       pte_ofs = pte_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
+                       pte += pte_ofs;
+                       for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn;
                             pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) {
                                pgprot_t prot = PAGE_KERNEL;
 
                                if (is_kernel_text(addr))
                                        prot = PAGE_KERNEL_EXEC;
 
+                               pages_4k++;
                                set_pte(pte, pfn_pte(pfn, prot));
                        }
-                       max_pfn_mapped = pfn;
                }
        }
-}
-
-static inline int page_kills_ppro(unsigned long pagenr)
-{
-       if (pagenr >= 0x70000 && pagenr <= 0x7003F)
-               return 1;
-       return 0;
+       update_page_count(PG_LEVEL_2M, pages_2m);
+       update_page_count(PG_LEVEL_4K, pages_4k);
 }
 
 /*
@@ -287,29 +318,62 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
        pkmap_page_table = pte;
 }
 
-void __init add_one_highpage_init(struct page *page, int pfn, int bad_ppro)
+static void __init add_one_highpage_init(struct page *page, int pfn)
 {
-       if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) {
-               ClearPageReserved(page);
-               init_page_count(page);
-               __free_page(page);
-               totalhigh_pages++;
-       } else
-               SetPageReserved(page);
+       ClearPageReserved(page);
+       init_page_count(page);
+       __free_page(page);
+       totalhigh_pages++;
 }
 
-#ifndef CONFIG_NUMA
-static void __init set_highmem_pages_init(int bad_ppro)
+struct add_highpages_data {
+       unsigned long start_pfn;
+       unsigned long end_pfn;
+};
+
+static int __init add_highpages_work_fn(unsigned long start_pfn,
+                                        unsigned long end_pfn, void *datax)
 {
-       int pfn;
+       int node_pfn;
+       struct page *page;
+       unsigned long final_start_pfn, final_end_pfn;
+       struct add_highpages_data *data;
 
-       for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) {
-               /*
-                * Holes under sparsemem might not have no mem_map[]:
-                */
-               if (pfn_valid(pfn))
-                       add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro);
+       data = (struct add_highpages_data *)datax;
+
+       final_start_pfn = max(start_pfn, data->start_pfn);
+       final_end_pfn = min(end_pfn, data->end_pfn);
+       if (final_start_pfn >= final_end_pfn)
+               return 0;
+
+       for (node_pfn = final_start_pfn; node_pfn < final_end_pfn;
+            node_pfn++) {
+               if (!pfn_valid(node_pfn))
+                       continue;
+               page = pfn_to_page(node_pfn);
+               add_one_highpage_init(page, node_pfn);
        }
+
+       return 0;
+
+}
+
+void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn,
+                                             unsigned long end_pfn)
+{
+       struct add_highpages_data data;
+
+       data.start_pfn = start_pfn;
+       data.end_pfn = end_pfn;
+
+       work_with_active_regions(nid, add_highpages_work_fn, &data);
+}
+
+#ifndef CONFIG_NUMA
+static void __init set_highmem_pages_init(void)
+{
+       add_highpages_with_active_regions(0, highstart_pfn, highend_pfn);
+
        totalram_pages += totalhigh_pages;
 }
 #endif /* !CONFIG_NUMA */
@@ -317,14 +381,9 @@ static void __init set_highmem_pages_init(int bad_ppro)
 #else
 # define kmap_init()                           do { } while (0)
 # define permanent_kmaps_init(pgd_base)                do { } while (0)
-# define set_highmem_pages_init(bad_ppro)      do { } while (0)
+# define set_highmem_pages_init()      do { } while (0)
 #endif /* CONFIG_HIGHMEM */
 
-pteval_t __PAGE_KERNEL = _PAGE_KERNEL;
-EXPORT_SYMBOL(__PAGE_KERNEL);
-
-pteval_t __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC;
-
 void __init native_pagetable_setup_start(pgd_t *base)
 {
        unsigned long pfn, va;
@@ -380,27 +439,10 @@ void __init native_pagetable_setup_done(pgd_t *base)
  * be partially populated, and so it avoids stomping on any existing
  * mappings.
  */
-static void __init pagetable_init(void)
+static void __init early_ioremap_page_table_range_init(pgd_t *pgd_base)
 {
-       pgd_t *pgd_base = swapper_pg_dir;
        unsigned long vaddr, end;
 
-       paravirt_pagetable_setup_start(pgd_base);
-
-       /* Enable PSE if available */
-       if (cpu_has_pse)
-               set_in_cr4(X86_CR4_PSE);
-
-       /* Enable PGE if available */
-       if (cpu_has_pge) {
-               set_in_cr4(X86_CR4_PGE);
-               __PAGE_KERNEL |= _PAGE_GLOBAL;
-               __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
-       }
-
-       kernel_physical_mapping_init(pgd_base);
-       remap_numa_kva();
-
        /*
         * Fixed mappings, only the page table structure has to be
         * created - mappings will be set by set_fixmap():
@@ -410,6 +452,13 @@ static void __init pagetable_init(void)
        end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
        page_table_range_init(vaddr, end, pgd_base);
        early_ioremap_reset();
+}
+
+static void __init pagetable_init(void)
+{
+       pgd_t *pgd_base = swapper_pg_dir;
+
+       paravirt_pagetable_setup_start(pgd_base);
 
        permanent_kmaps_init(pgd_base);
 
@@ -456,7 +505,7 @@ void zap_low_mappings(void)
 
 int nx_enabled;
 
-pteval_t __supported_pte_mask __read_mostly = ~_PAGE_NX;
+pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
 #ifdef CONFIG_X86_PAE
@@ -509,27 +558,318 @@ static void __init set_nx(void)
 }
 #endif
 
+/* user-defined highmem size */
+static unsigned int highmem_pages = -1;
+
 /*
- * paging_init() sets up the page tables - note that the first 8MB are
- * already mapped by head.S.
- *
- * This routines also unmaps the page at virtual kernel address 0, so
- * that we can trap those pesky NULL-reference errors in the kernel.
+ * highmem=size forces highmem to be exactly 'size' bytes.
+ * This works even on boxes that have no highmem otherwise.
+ * This also works to reduce highmem size on bigger boxes.
  */
-void __init paging_init(void)
+static int __init parse_highmem(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+
+       highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT;
+       return 0;
+}
+early_param("highmem", parse_highmem);
+
+/*
+ * Determine low and high memory ranges:
+ */
+void __init find_low_pfn_range(void)
 {
+       /* it could update max_pfn */
+
+       /* max_low_pfn is 0, we already have early_res support */
+
+       max_low_pfn = max_pfn;
+       if (max_low_pfn > MAXMEM_PFN) {
+               if (highmem_pages == -1)
+                       highmem_pages = max_pfn - MAXMEM_PFN;
+               if (highmem_pages + MAXMEM_PFN < max_pfn)
+                       max_pfn = MAXMEM_PFN + highmem_pages;
+               if (highmem_pages + MAXMEM_PFN > max_pfn) {
+                       printk(KERN_WARNING "only %luMB highmem pages "
+                               "available, ignoring highmem size of %uMB.\n",
+                               pages_to_mb(max_pfn - MAXMEM_PFN),
+                               pages_to_mb(highmem_pages));
+                       highmem_pages = 0;
+               }
+               max_low_pfn = MAXMEM_PFN;
+#ifndef CONFIG_HIGHMEM
+               /* Maximum memory usable is what is directly addressable */
+               printk(KERN_WARNING "Warning only %ldMB will be used.\n",
+                                       MAXMEM>>20);
+               if (max_pfn > MAX_NONPAE_PFN)
+                       printk(KERN_WARNING
+                                "Use a HIGHMEM64G enabled kernel.\n");
+               else
+                       printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+               max_pfn = MAXMEM_PFN;
+#else /* !CONFIG_HIGHMEM */
+#ifndef CONFIG_HIGHMEM64G
+               if (max_pfn > MAX_NONPAE_PFN) {
+                       max_pfn = MAX_NONPAE_PFN;
+                       printk(KERN_WARNING "Warning only 4GB will be used."
+                               "Use a HIGHMEM64G enabled kernel.\n");
+               }
+#endif /* !CONFIG_HIGHMEM64G */
+#endif /* !CONFIG_HIGHMEM */
+       } else {
+               if (highmem_pages == -1)
+                       highmem_pages = 0;
+#ifdef CONFIG_HIGHMEM
+               if (highmem_pages >= max_pfn) {
+                       printk(KERN_ERR "highmem size specified (%uMB) is "
+                               "bigger than pages available (%luMB)!.\n",
+                               pages_to_mb(highmem_pages),
+                               pages_to_mb(max_pfn));
+                       highmem_pages = 0;
+               }
+               if (highmem_pages) {
+                       if (max_low_pfn - highmem_pages <
+                           64*1024*1024/PAGE_SIZE){
+                               printk(KERN_ERR "highmem size %uMB results in "
+                               "smaller than 64MB lowmem, ignoring it.\n"
+                                       , pages_to_mb(highmem_pages));
+                               highmem_pages = 0;
+                       }
+                       max_low_pfn -= highmem_pages;
+               }
+#else
+               if (highmem_pages)
+                       printk(KERN_ERR "ignoring highmem size on non-highmem"
+                                       " kernel!\n");
+#endif
+       }
+}
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+void __init initmem_init(unsigned long start_pfn,
+                                 unsigned long end_pfn)
+{
+#ifdef CONFIG_HIGHMEM
+       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);
+       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);
+       num_physpages = max_low_pfn;
+       high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
+#endif
+#ifdef CONFIG_FLATMEM
+       max_mapnr = num_physpages;
+#endif
+       printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+                       pages_to_mb(max_low_pfn));
+
+       setup_bootmem_allocator();
+}
+#endif /* !CONFIG_NEED_MULTIPLE_NODES */
+
+static void __init zone_sizes_init(void)
+{
+       unsigned long max_zone_pfns[MAX_NR_ZONES];
+       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+       max_zone_pfns[ZONE_DMA] =
+               virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
+       max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
+#endif
+
+       free_area_init_nodes(max_zone_pfns);
+}
+
+void __init setup_bootmem_allocator(void)
+{
+       int i;
+       unsigned long bootmap_size, bootmap;
+       /*
+        * Initialize the boot-time allocator (with low memory only):
+        */
+       bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT;
+       bootmap = find_e820_area(min_low_pfn<<PAGE_SHIFT,
+                                max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
+                                PAGE_SIZE);
+       if (bootmap == -1L)
+               panic("Cannot find bootmem map of size %ld\n", bootmap_size);
+       reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
+
+       /* don't touch min_low_pfn */
+       bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT,
+                                        min_low_pfn, max_low_pfn);
+       printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
+                max_pfn_mapped<<PAGE_SHIFT);
+       printk(KERN_INFO "  low ram: %08lx - %08lx\n",
+                min_low_pfn<<PAGE_SHIFT, max_low_pfn<<PAGE_SHIFT);
+       printk(KERN_INFO "  bootmap %08lx - %08lx\n",
+                bootmap, bootmap + bootmap_size);
+       for_each_online_node(i)
+               free_bootmem_with_active_regions(i, max_low_pfn);
+       early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
+
+       after_init_bootmem = 1;
+}
+
+static void __init find_early_table_space(unsigned long end)
+{
+       unsigned long puds, pmds, ptes, tables, start;
+
+       puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
+       tables = PAGE_ALIGN(puds * sizeof(pud_t));
+
+       pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
+       tables += PAGE_ALIGN(pmds * sizeof(pmd_t));
+
+       if (cpu_has_pse) {
+               unsigned long extra;
+
+               extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
+               extra += PMD_SIZE;
+               ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       } else
+               ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       tables += PAGE_ALIGN(ptes * sizeof(pte_t));
+
+       /* for fixmap */
+       tables += PAGE_SIZE * 2;
+
+       /*
+        * RED-PEN putting page tables only on node 0 could
+        * cause a hotspot and fill up ZONE_DMA. The page tables
+        * need roughly 0.5KB per GB.
+        */
+       start = 0x7000;
+       table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
+                                       tables, PAGE_SIZE);
+       if (table_start == -1UL)
+               panic("Cannot find space for the kernel page tables");
+
+       table_start >>= PAGE_SHIFT;
+       table_end = table_start;
+       table_top = table_start + (tables>>PAGE_SHIFT);
+
+       printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
+               end, table_start << PAGE_SHIFT,
+               (table_start << PAGE_SHIFT) + tables);
+}
+
+unsigned long __init_refok init_memory_mapping(unsigned long start,
+                                               unsigned long end)
+{
+       pgd_t *pgd_base = swapper_pg_dir;
+       unsigned long start_pfn, end_pfn;
+       unsigned long big_page_start;
+
+       /*
+        * Find space for the kernel direct mapping tables.
+        */
+       if (!after_init_bootmem)
+               find_early_table_space(end);
+
 #ifdef CONFIG_X86_PAE
        set_nx();
        if (nx_enabled)
                printk(KERN_INFO "NX (Execute Disable) protection: active\n");
 #endif
-       pagetable_init();
+
+       /* Enable PSE if available */
+       if (cpu_has_pse)
+               set_in_cr4(X86_CR4_PSE);
+
+       /* Enable PGE if available */
+       if (cpu_has_pge) {
+               set_in_cr4(X86_CR4_PGE);
+               __supported_pte_mask |= _PAGE_GLOBAL;
+       }
+
+       /*
+        * Don't use a large page for the first 2/4MB of memory
+        * because there are often fixed size MTRRs in there
+        * and overlapping MTRRs into large pages can cause
+        * slowdowns.
+        */
+       big_page_start = PMD_SIZE;
+
+       if (start < big_page_start) {
+               start_pfn = start >> PAGE_SHIFT;
+               end_pfn = min(big_page_start>>PAGE_SHIFT, end>>PAGE_SHIFT);
+       } else {
+               /* head is not big page alignment ? */
+               start_pfn = start >> PAGE_SHIFT;
+               end_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT)
+                                << (PMD_SHIFT - PAGE_SHIFT);
+       }
+       if (start_pfn < end_pfn)
+               kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn, 0);
+
+       /* big page range */
+       start_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT)
+                        << (PMD_SHIFT - PAGE_SHIFT);
+       if (start_pfn < (big_page_start >> PAGE_SHIFT))
+               start_pfn =  big_page_start >> PAGE_SHIFT;
+       end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
+       if (start_pfn < end_pfn)
+               kernel_physical_mapping_init(pgd_base, start_pfn, end_pfn,
+                                               cpu_has_pse);
+
+       /* tail is not big page alignment ? */
+       start_pfn = end_pfn;
+       if (start_pfn > (big_page_start>>PAGE_SHIFT)) {
+               end_pfn = end >> PAGE_SHIFT;
+               if (start_pfn < end_pfn)
+                       kernel_physical_mapping_init(pgd_base, start_pfn,
+                                                        end_pfn, 0);
+       }
+
+       early_ioremap_page_table_range_init(pgd_base);
 
        load_cr3(swapper_pg_dir);
 
        __flush_tlb_all();
 
+       if (!after_init_bootmem)
+               reserve_early(table_start << PAGE_SHIFT,
+                                table_end << PAGE_SHIFT, "PGTABLE");
+
+       return end >> PAGE_SHIFT;
+}
+
+
+/*
+ * paging_init() sets up the page tables - note that the first 8MB are
+ * already mapped by head.S.
+ *
+ * This routines also unmaps the page at virtual kernel address 0, so
+ * that we can trap those pesky NULL-reference errors in the kernel.
+ */
+void __init paging_init(void)
+{
+       pagetable_init();
+
+       __flush_tlb_all();
+
        kmap_init();
+
+       /*
+        * NOTE: at this point the bootmem allocator is fully available.
+        */
+       sparse_init();
+       zone_sizes_init();
+
+       paravirt_post_allocator_init();
 }
 
 /*
@@ -564,23 +904,10 @@ static struct kcore_list kcore_mem, kcore_vmalloc;
 void __init mem_init(void)
 {
        int codesize, reservedpages, datasize, initsize;
-       int tmp, bad_ppro;
+       int tmp;
 
 #ifdef CONFIG_FLATMEM
        BUG_ON(!mem_map);
-#endif
-       bad_ppro = ppro_with_ram_bug();
-
-#ifdef CONFIG_HIGHMEM
-       /* check that fixmap and pkmap do not overlap */
-       if (PKMAP_BASE + LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
-               printk(KERN_ERR
-                       "fixmap and kmap areas overlap - this will crash\n");
-               printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n",
-                               PKMAP_BASE, PKMAP_BASE + LAST_PKMAP*PAGE_SIZE,
-                               FIXADDR_START);
-               BUG();
-       }
 #endif
        /* this will put all low memory onto the freelists */
        totalram_pages += free_all_bootmem();
@@ -593,7 +920,7 @@ void __init mem_init(void)
                if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
                        reservedpages++;
 
-       set_highmem_pages_init(bad_ppro);
+       set_highmem_pages_init();
 
        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
@@ -614,7 +941,6 @@ void __init mem_init(void)
                (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
               );
 
-#if 1 /* double-sanity-check paranoia */
        printk(KERN_INFO "virtual kernel memory layout:\n"
                "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_HIGHMEM
@@ -655,7 +981,6 @@ void __init mem_init(void)
 #endif
        BUG_ON(VMALLOC_START                            > VMALLOC_END);
        BUG_ON((unsigned long)high_memory               > VMALLOC_START);
-#endif /* double-sanity-check paranoia */
 
        if (boot_cpu_data.wp_works_ok < 0)
                test_wp_bit();
@@ -784,3 +1109,9 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        free_init_pages("initrd memory", start, end);
 }
 #endif
+
+int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
+                                  int flags)
+{
+       return reserve_bootmem(phys, len, flags);
+}
index 819dad973b1375bc5da5a90297c5c41788d2a652..a25cc6fa2207262131dcec567f3b43ce861d0f3f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/swap.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/initrd.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
 #include <asm/numa.h>
 #include <asm/cacheflush.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);
@@ -135,26 +144,17 @@ static __init void *spp_getpage(void)
        return ptr;
 }
 
-static __init void
-set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
+void
+set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte)
 {
-       pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte, new_pte;
-
-       pr_debug("set_pte_phys %lx to %lx\n", vaddr, phys);
+       pte_t *pte;
 
-       pgd = pgd_offset_k(vaddr);
-       if (pgd_none(*pgd)) {
-               printk(KERN_ERR
-                       "PGD FIXMAP MISSING, it should be setup in head.S!\n");
-               return;
-       }
-       pud = pud_offset(pgd, vaddr);
+       pud = pud_page + pud_index(vaddr);
        if (pud_none(*pud)) {
                pmd = (pmd_t *) spp_getpage();
-               set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
+               pud_populate(&init_mm, pud, pmd);
                if (pmd != pmd_offset(pud, 0)) {
                        printk(KERN_ERR "PAGETABLE BUG #01! %p <-> %p\n",
                                pmd, pmd_offset(pud, 0));
@@ -164,13 +164,12 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
        pmd = pmd_offset(pud, vaddr);
        if (pmd_none(*pmd)) {
                pte = (pte_t *) spp_getpage();
-               set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
+               pmd_populate_kernel(&init_mm, pmd, pte);
                if (pte != pte_offset_kernel(pmd, 0)) {
                        printk(KERN_ERR "PAGETABLE BUG #02!\n");
                        return;
                }
        }
-       new_pte = pfn_pte(phys >> PAGE_SHIFT, prot);
 
        pte = pte_offset_kernel(pmd, vaddr);
        if (!pte_none(*pte) && pte_val(new_pte) &&
@@ -185,6 +184,64 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
        __flush_tlb_one(vaddr);
 }
 
+void
+set_pte_vaddr(unsigned long vaddr, pte_t pteval)
+{
+       pgd_t *pgd;
+       pud_t *pud_page;
+
+       pr_debug("set_pte_vaddr %lx to %lx\n", vaddr, native_pte_val(pteval));
+
+       pgd = pgd_offset_k(vaddr);
+       if (pgd_none(*pgd)) {
+               printk(KERN_ERR
+                       "PGD FIXMAP MISSING, it should be setup in head.S!\n");
+               return;
+       }
+       pud_page = (pud_t*)pgd_page_vaddr(*pgd);
+       set_pte_vaddr_pud(pud_page, vaddr, pteval);
+}
+
+/*
+ * Create large page table mappings for a range of physical addresses.
+ */
+static void __init __init_extra_mapping(unsigned long phys, unsigned long size,
+                                               pgprot_t prot)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       BUG_ON((phys & ~PMD_MASK) || (size & ~PMD_MASK));
+       for (; size; phys += PMD_SIZE, size -= PMD_SIZE) {
+               pgd = pgd_offset_k((unsigned long)__va(phys));
+               if (pgd_none(*pgd)) {
+                       pud = (pud_t *) spp_getpage();
+                       set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE |
+                                               _PAGE_USER));
+               }
+               pud = pud_offset(pgd, (unsigned long)__va(phys));
+               if (pud_none(*pud)) {
+                       pmd = (pmd_t *) spp_getpage();
+                       set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE |
+                                               _PAGE_USER));
+               }
+               pmd = pmd_offset(pud, phys);
+               BUG_ON(!pmd_none(*pmd));
+               set_pmd(pmd, __pmd(phys | pgprot_val(prot)));
+       }
+}
+
+void __init init_extra_mapping_wb(unsigned long phys, unsigned long size)
+{
+       __init_extra_mapping(phys, size, PAGE_KERNEL_LARGE);
+}
+
+void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)
+{
+       __init_extra_mapping(phys, size, PAGE_KERNEL_LARGE_NOCACHE);
+}
+
 /*
  * The head.S code sets up the kernel high mapping:
  *
@@ -213,20 +270,9 @@ void __init cleanup_highmap(void)
        }
 }
 
-/* NOTE: this is meant to be run only at boot */
-void __init __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
-{
-       unsigned long address = __fix_to_virt(idx);
-
-       if (idx >= __end_of_fixed_addresses) {
-               printk(KERN_ERR "Invalid __set_fixmap\n");
-               return;
-       }
-       set_pte_phys(address, phys, prot);
-}
-
 static unsigned long __initdata table_start;
 static unsigned long __meminitdata table_end;
+static unsigned long __meminitdata table_top;
 
 static __meminit void *alloc_low_page(unsigned long *phys)
 {
@@ -240,7 +286,7 @@ static __meminit void *alloc_low_page(unsigned long *phys)
                return adr;
        }
 
-       if (pfn >= end_pfn)
+       if (pfn >= table_top)
                panic("alloc_low_page: ran out of memory");
 
        adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
@@ -257,65 +303,61 @@ static __meminit void unmap_low_page(void *adr)
        early_iounmap(adr, PAGE_SIZE);
 }
 
-/* Must run before zap_low_mappings */
-__meminit void *early_ioremap(unsigned long addr, unsigned long size)
+static unsigned long __meminit
+phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end)
 {
-       pmd_t *pmd, *last_pmd;
-       unsigned long vaddr;
-       int i, pmds;
+       unsigned pages = 0;
+       unsigned long last_map_addr = end;
+       int i;
+
+       pte_t *pte = pte_page + pte_index(addr);
 
-       pmds = ((addr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
-       vaddr = __START_KERNEL_map;
-       pmd = level2_kernel_pgt;
-       last_pmd = level2_kernel_pgt + PTRS_PER_PMD - 1;
+       for(i = pte_index(addr); i < PTRS_PER_PTE; i++, addr += PAGE_SIZE, pte++) {
 
-       for (; pmd <= last_pmd; pmd++, vaddr += PMD_SIZE) {
-               for (i = 0; i < pmds; i++) {
-                       if (pmd_present(pmd[i]))
-                               goto continue_outer_loop;
+               if (addr >= end) {
+                       if (!after_bootmem) {
+                               for(; i < PTRS_PER_PTE; i++, pte++)
+                                       set_pte(pte, __pte(0));
+                       }
+                       break;
                }
-               vaddr += addr & ~PMD_MASK;
-               addr &= PMD_MASK;
 
-               for (i = 0; i < pmds; i++, addr += PMD_SIZE)
-                       set_pmd(pmd+i, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
-               __flush_tlb_all();
+               if (pte_val(*pte))
+                       continue;
 
-               return (void *)vaddr;
-continue_outer_loop:
-               ;
+               if (0)
+                       printk("   pte=%p addr=%lx pte=%016lx\n",
+                              pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte);
+               set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL));
+               last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE;
+               pages++;
        }
-       printk(KERN_ERR "early_ioremap(0x%lx, %lu) failed\n", addr, size);
+       update_page_count(PG_LEVEL_4K, pages);
 
-       return NULL;
+       return last_map_addr;
 }
 
-/*
- * To avoid virtual aliases later:
- */
-__meminit void early_iounmap(void *addr, unsigned long size)
+static unsigned long __meminit
+phys_pte_update(pmd_t *pmd, unsigned long address, unsigned long end)
 {
-       unsigned long vaddr;
-       pmd_t *pmd;
-       int i, pmds;
-
-       vaddr = (unsigned long)addr;
-       pmds = ((vaddr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
-       pmd = level2_kernel_pgt + pmd_index(vaddr);
+       pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd);
 
-       for (i = 0; i < pmds; i++)
-               pmd_clear(pmd + i);
-
-       __flush_tlb_all();
+       return phys_pte_init(pte, address, end);
 }
 
 static unsigned long __meminit
-phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
+phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
+                        unsigned long page_size_mask)
 {
+       unsigned long pages = 0;
+       unsigned long last_map_addr = end;
+
        int i = pmd_index(address);
 
        for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
+               unsigned long pte_phys;
                pmd_t *pmd = pmd_page + pmd_index(address);
+               pte_t *pte;
 
                if (address >= end) {
                        if (!after_bootmem) {
@@ -325,31 +367,50 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
                        break;
                }
 
-               if (pmd_val(*pmd))
+               if (pmd_val(*pmd)) {
+                       if (!pmd_large(*pmd))
+                               last_map_addr = phys_pte_update(pmd, address,
+                                                                end);
+                       continue;
+               }
+
+               if (page_size_mask & (1<<PG_LEVEL_2M)) {
+                       pages++;
+                       set_pte((pte_t *)pmd,
+                               pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
+                       last_map_addr = (address & PMD_MASK) + PMD_SIZE;
                        continue;
+               }
 
-               set_pte((pte_t *)pmd,
-                       pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
+               pte = alloc_low_page(&pte_phys);
+               last_map_addr = phys_pte_init(pte, address, end);
+               unmap_low_page(pte);
+
+               pmd_populate_kernel(&init_mm, pmd, __va(pte_phys));
        }
-       return address;
+       update_page_count(PG_LEVEL_2M, pages);
+       return last_map_addr;
 }
 
 static unsigned long __meminit
-phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end)
+phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end,
+                        unsigned long page_size_mask)
 {
        pmd_t *pmd = pmd_offset(pud, 0);
        unsigned long last_map_addr;
 
        spin_lock(&init_mm.page_table_lock);
-       last_map_addr = phys_pmd_init(pmd, address, end);
+       last_map_addr = phys_pmd_init(pmd, address, end, page_size_mask);
        spin_unlock(&init_mm.page_table_lock);
        __flush_tlb_all();
        return last_map_addr;
 }
 
 static unsigned long __meminit
-phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
+phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
+                        unsigned long page_size_mask)
 {
+       unsigned long pages = 0;
        unsigned long last_map_addr = end;
        int i = pud_index(addr);
 
@@ -369,11 +430,13 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
 
                if (pud_val(*pud)) {
                        if (!pud_large(*pud))
-                               last_map_addr = phys_pmd_update(pud, addr, end);
+                               last_map_addr = phys_pmd_update(pud, addr, end,
+                                                        page_size_mask);
                        continue;
                }
 
-               if (direct_gbpages) {
+               if (page_size_mask & (1<<PG_LEVEL_1G)) {
+                       pages++;
                        set_pte((pte_t *)pud,
                                pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
                        last_map_addr = (addr & PUD_MASK) + PUD_SIZE;
@@ -383,27 +446,50 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end)
                pmd = alloc_low_page(&pmd_phys);
 
                spin_lock(&init_mm.page_table_lock);
-               set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
-               last_map_addr = phys_pmd_init(pmd, addr, end);
+               last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask);
+               unmap_low_page(pmd);
+               pud_populate(&init_mm, pud, __va(pmd_phys));
                spin_unlock(&init_mm.page_table_lock);
 
-               unmap_low_page(pmd);
        }
        __flush_tlb_all();
+       update_page_count(PG_LEVEL_1G, pages);
 
-       return last_map_addr >> PAGE_SHIFT;
+       return last_map_addr;
+}
+
+static unsigned long __meminit
+phys_pud_update(pgd_t *pgd, unsigned long addr, unsigned long end,
+                unsigned long page_size_mask)
+{
+       pud_t *pud;
+
+       pud = (pud_t *)pgd_page_vaddr(*pgd);
+
+       return phys_pud_init(pud, addr, end, page_size_mask);
 }
 
 static void __init find_early_table_space(unsigned long end)
 {
-       unsigned long puds, pmds, tables, start;
+       unsigned long puds, pmds, ptes, tables, start;
 
        puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
        tables = round_up(puds * sizeof(pud_t), PAGE_SIZE);
-       if (!direct_gbpages) {
+       if (direct_gbpages) {
+               unsigned long extra;
+               extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT);
+               pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT;
+       } else
                pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
-               tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE);
-       }
+       tables += round_up(pmds * sizeof(pmd_t), PAGE_SIZE);
+
+       if (cpu_has_pse) {
+               unsigned long extra;
+               extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
+               ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       } else
+               ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       tables += round_up(ptes * sizeof(pte_t), PAGE_SIZE);
 
        /*
         * RED-PEN putting page tables only on node 0 could
@@ -417,10 +503,10 @@ static void __init find_early_table_space(unsigned long end)
 
        table_start >>= PAGE_SHIFT;
        table_end = table_start;
+       table_top = table_start + (tables >> PAGE_SHIFT);
 
-       early_printk("kernel direct mapping tables up to %lx @ %lx-%lx\n",
-               end, table_start << PAGE_SHIFT,
-               (table_start << PAGE_SHIFT) + tables);
+       printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
+               end, table_start << PAGE_SHIFT, table_top << PAGE_SHIFT);
 }
 
 static void __init init_gbpages(void)
@@ -431,7 +517,7 @@ static void __init init_gbpages(void)
                direct_gbpages = 0;
 }
 
-#ifdef CONFIG_MEMTEST_BOOTPARAM
+#ifdef CONFIG_MEMTEST
 
 static void __init memtest(unsigned long start_phys, unsigned long size,
                                 unsigned pattern)
@@ -493,7 +579,8 @@ static void __init memtest(unsigned long start_phys, unsigned long size,
 
 }
 
-static int memtest_pattern __initdata = CONFIG_MEMTEST_BOOTPARAM_VALUE;
+/* default is disabled */
+static int memtest_pattern __initdata;
 
 static int __init parse_memtest(char *arg)
 {
@@ -542,15 +629,85 @@ static void __init early_memtest(unsigned long start, unsigned long end)
 }
 #endif
 
+static unsigned long __init kernel_physical_mapping_init(unsigned long start,
+                                               unsigned long end,
+                                               unsigned long page_size_mask)
+{
+
+       unsigned long next, last_map_addr = end;
+
+       start = (unsigned long)__va(start);
+       end = (unsigned long)__va(end);
+
+       for (; start < end; start = next) {
+               pgd_t *pgd = pgd_offset_k(start);
+               unsigned long pud_phys;
+               pud_t *pud;
+
+               next = start + PGDIR_SIZE;
+               if (next > end)
+                       next = end;
+
+               if (pgd_val(*pgd)) {
+                       last_map_addr = phys_pud_update(pgd, __pa(start),
+                                                __pa(end), page_size_mask);
+                       continue;
+               }
+
+               if (after_bootmem)
+                       pud = pud_offset(pgd, start & PGDIR_MASK);
+               else
+                       pud = alloc_low_page(&pud_phys);
+
+               last_map_addr = phys_pud_init(pud, __pa(start), __pa(next),
+                                                page_size_mask);
+               unmap_low_page(pud);
+               pgd_populate(&init_mm, pgd_offset_k(start),
+                            __va(pud_phys));
+       }
+
+       return last_map_addr;
+}
+
+struct map_range {
+       unsigned long start;
+       unsigned long end;
+       unsigned page_size_mask;
+};
+
+#define NR_RANGE_MR 5
+
+static int save_mr(struct map_range *mr, int nr_range,
+                  unsigned long start_pfn, unsigned long end_pfn,
+                  unsigned long page_size_mask)
+{
+
+       if (start_pfn < end_pfn) {
+               if (nr_range >= NR_RANGE_MR)
+                       panic("run out of range for init_memory_mapping\n");
+               mr[nr_range].start = start_pfn<<PAGE_SHIFT;
+               mr[nr_range].end   = end_pfn<<PAGE_SHIFT;
+               mr[nr_range].page_size_mask = page_size_mask;
+               nr_range++;
+       }
+
+       return nr_range;
+}
+
 /*
  * Setup the direct mapping of the physical memory at PAGE_OFFSET.
  * This runs before bootmem is initialized and gets pages directly from
  * the physical memory. To access them they are temporarily mapped.
  */
-unsigned long __init_refok init_memory_mapping(unsigned long start, unsigned long end)
+unsigned long __init_refok init_memory_mapping(unsigned long start,
+                                              unsigned long end)
 {
-       unsigned long next, last_map_addr = end;
-       unsigned long start_phys = start, end_phys = end;
+       unsigned long last_map_addr = 0;
+       unsigned long page_size_mask = 0;
+       unsigned long start_pfn, end_pfn;
+
+       struct map_range mr[NR_RANGE_MR];
+       int nr_range, i;
 
        printk(KERN_INFO "init_memory_mapping\n");
 
@@ -561,48 +718,115 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, unsigned lon
         * memory mapped. Unfortunately this is done currently before the
         * nodes are discovered.
         */
-       if (!after_bootmem) {
+       if (!after_bootmem)
                init_gbpages();
-               find_early_table_space(end);
+
+       if (direct_gbpages)
+               page_size_mask |= 1 << PG_LEVEL_1G;
+       if (cpu_has_pse)
+               page_size_mask |= 1 << PG_LEVEL_2M;
+
+       memset(mr, 0, sizeof(mr));
+       nr_range = 0;
+
+       /* head if not big page alignment ?*/
+       start_pfn = start >> PAGE_SHIFT;
+       end_pfn = ((start + (PMD_SIZE - 1)) >> PMD_SHIFT)
+                       << (PMD_SHIFT - PAGE_SHIFT);
+       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
+
+       /* big page (2M) range*/
+       start_pfn = ((start + (PMD_SIZE - 1))>>PMD_SHIFT)
+                        << (PMD_SHIFT - PAGE_SHIFT);
+       end_pfn = ((start + (PUD_SIZE - 1))>>PUD_SHIFT)
+                        << (PUD_SHIFT - PAGE_SHIFT);
+       if (end_pfn > ((end>>PUD_SHIFT)<<(PUD_SHIFT - PAGE_SHIFT)))
+               end_pfn = ((end>>PUD_SHIFT)<<(PUD_SHIFT - PAGE_SHIFT));
+       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
+                       page_size_mask & (1<<PG_LEVEL_2M));
+
+       /* big page (1G) range */
+       start_pfn = end_pfn;
+       end_pfn = (end>>PUD_SHIFT) << (PUD_SHIFT - PAGE_SHIFT);
+       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
+                               page_size_mask &
+                                ((1<<PG_LEVEL_2M)|(1<<PG_LEVEL_1G)));
+
+       /* tail is not big page (1G) alignment */
+       start_pfn = end_pfn;
+       end_pfn = (end>>PMD_SHIFT) << (PMD_SHIFT - PAGE_SHIFT);
+       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn,
+                       page_size_mask & (1<<PG_LEVEL_2M));
+
+       /* tail is not big page (2M) alignment */
+       start_pfn = end_pfn;
+       end_pfn = end>>PAGE_SHIFT;
+       nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
+
+       /* try to merge same page size and continuous */
+       for (i = 0; nr_range > 1 && i < nr_range - 1; i++) {
+               unsigned long old_start;
+               if (mr[i].end != mr[i+1].start ||
+                   mr[i].page_size_mask != mr[i+1].page_size_mask)
+                       continue;
+               /* move it */
+               old_start = mr[i].start;
+               memmove(&mr[i], &mr[i+1],
+                        (nr_range - 1 - i) * sizeof (struct map_range));
+               mr[i].start = old_start;
+               nr_range--;
        }
 
-       start = (unsigned long)__va(start);
-       end = (unsigned long)__va(end);
+       for (i = 0; i < nr_range; i++)
+               printk(KERN_DEBUG " %010lx - %010lx page %s\n",
+                               mr[i].start, mr[i].end,
+                       (mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
+                        (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
 
-       for (; start < end; start = next) {
-               pgd_t *pgd = pgd_offset_k(start);
-               unsigned long pud_phys;
-               pud_t *pud;
-
-               if (after_bootmem)
-                       pud = pud_offset(pgd, start & PGDIR_MASK);
-               else
-                       pud = alloc_low_page(&pud_phys);
+       if (!after_bootmem)
+               find_early_table_space(end);
 
-               next = start + PGDIR_SIZE;
-               if (next > end)
-                       next = end;
-               last_map_addr = phys_pud_init(pud, __pa(start), __pa(next));
-               if (!after_bootmem)
-                       set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
-               unmap_low_page(pud);
-       }
+       for (i = 0; i < nr_range; i++)
+               last_map_addr = kernel_physical_mapping_init(
+                                       mr[i].start, mr[i].end,
+                                       mr[i].page_size_mask);
 
        if (!after_bootmem)
                mmu_cr4_features = read_cr4();
        __flush_tlb_all();
 
-       if (!after_bootmem)
+       if (!after_bootmem && table_end > table_start)
                reserve_early(table_start << PAGE_SHIFT,
                                 table_end << PAGE_SHIFT, "PGTABLE");
 
+       printk(KERN_INFO "last_map_addr: %lx end: %lx\n",
+                        last_map_addr, end);
+
        if (!after_bootmem)
-               early_memtest(start_phys, end_phys);
+               early_memtest(start, end);
 
-       return last_map_addr;
+       return last_map_addr >> PAGE_SHIFT;
 }
 
 #ifndef CONFIG_NUMA
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned long bootmap_size, bootmap;
+
+       bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
+       bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
+                                PAGE_SIZE);
+       if (bootmap == -1L)
+               panic("Cannot find bootmem map of size %ld\n", bootmap_size);
+       /* don't touch min_low_pfn */
+       bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT,
+                                        0, end_pfn);
+       e820_register_active_regions(0, start_pfn, end_pfn);
+       free_bootmem_with_active_regions(0, end_pfn);
+       early_res_to_bootmem(0, end_pfn<<PAGE_SHIFT);
+       reserve_bootmem(bootmap, bootmap_size, BOOTMEM_DEFAULT);
+}
+
 void __init paging_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES];
@@ -610,9 +834,9 @@ void __init paging_init(void)
        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] = end_pfn;
+       max_zone_pfns[ZONE_NORMAL] = max_pfn;
 
-       memory_present(0, 0, end_pfn);
+       memory_present(0, 0, max_pfn);
        sparse_init();
        free_area_init_nodes(max_zone_pfns);
 }
@@ -694,8 +918,8 @@ void __init mem_init(void)
 #else
        totalram_pages = free_all_bootmem();
 #endif
-       reservedpages = end_pfn - totalram_pages -
-                                       absent_pages_in_range(0, end_pfn);
+       reservedpages = max_pfn - totalram_pages -
+                                       absent_pages_in_range(0, max_pfn);
        after_bootmem = 1;
 
        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
@@ -714,7 +938,7 @@ void __init mem_init(void)
        printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
                                "%ldk reserved, %ldk data, %ldk init)\n",
                (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
-               end_pfn << (PAGE_SHIFT-10),
+               max_pfn << (PAGE_SHIFT-10),
                codesize >> 10,
                reservedpages << (PAGE_SHIFT-10),
                datasize >> 10,
@@ -799,24 +1023,26 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
+int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
+                                  int flags)
 {
 #ifdef CONFIG_NUMA
        int nid, next_nid;
+       int ret;
 #endif
        unsigned long pfn = phys >> PAGE_SHIFT;
 
-       if (pfn >= end_pfn) {
+       if (pfn >= max_pfn) {
                /*
                 * This can happen with kdump kernels when accessing
                 * firmware tables:
                 */
                if (pfn < max_pfn_mapped)
-                       return;
+                       return -EFAULT;
 
-               printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n",
+               printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %lu\n",
                                phys, len);
-               return;
+               return -EFAULT;
        }
 
        /* Should check here against the e820 map to avoid double free */
@@ -824,9 +1050,13 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
        nid = phys_to_nid(phys);
        next_nid = phys_to_nid(phys + len - 1);
        if (nid == next_nid)
-               reserve_bootmem_node(NODE_DATA(nid), phys, len, BOOTMEM_DEFAULT);
+               ret = reserve_bootmem_node(NODE_DATA(nid), phys, len, flags);
        else
-               reserve_bootmem(phys, len, BOOTMEM_DEFAULT);
+               ret = reserve_bootmem(phys, len, flags);
+
+       if (ret != 0)
+               return ret;
+
 #else
        reserve_bootmem(phys, len, BOOTMEM_DEFAULT);
 #endif
@@ -835,6 +1065,8 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
                dma_reserve += len / PAGE_SIZE;
                set_dma_reserve(dma_reserve);
        }
+
+       return 0;
 }
 
 int kern_addr_valid(unsigned long addr)
@@ -939,7 +1171,7 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
        pmd_t *pmd;
 
        for (; addr < end; addr = next) {
-               next = pmd_addr_end(addr, end);
+               void *p = NULL;
 
                pgd = vmemmap_pgd_populate(addr, node);
                if (!pgd)
@@ -949,33 +1181,51 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
                if (!pud)
                        return -ENOMEM;
 
-               pmd = pmd_offset(pud, addr);
-               if (pmd_none(*pmd)) {
-                       pte_t entry;
-                       void *p;
+               if (!cpu_has_pse) {
+                       next = (addr + PAGE_SIZE) & PAGE_MASK;
+                       pmd = vmemmap_pmd_populate(pud, addr, node);
+
+                       if (!pmd)
+                               return -ENOMEM;
+
+                       p = vmemmap_pte_populate(pmd, addr, node);
 
-                       p = vmemmap_alloc_block(PMD_SIZE, node);
                        if (!p)
                                return -ENOMEM;
 
-                       entry = pfn_pte(__pa(p) >> PAGE_SHIFT,
-                                                       PAGE_KERNEL_LARGE);
-                       set_pmd(pmd, __pmd(pte_val(entry)));
-
-                       /* check to see if we have contiguous blocks */
-                       if (p_end != p || node_start != node) {
-                               if (p_start)
-                                       printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n",
-                                               addr_start, addr_end-1, p_start, p_end-1, node_start);
-                               addr_start = addr;
-                               node_start = node;
-                               p_start = p;
-                       }
-                       addr_end = addr + PMD_SIZE;
-                       p_end = p + PMD_SIZE;
+                       addr_end = addr + PAGE_SIZE;
+                       p_end = p + PAGE_SIZE;
                } else {
-                       vmemmap_verify((pte_t *)pmd, node, addr, next);
+                       next = pmd_addr_end(addr, end);
+
+                       pmd = pmd_offset(pud, addr);
+                       if (pmd_none(*pmd)) {
+                               pte_t entry;
+
+                               p = vmemmap_alloc_block(PMD_SIZE, node);
+                               if (!p)
+                                       return -ENOMEM;
+
+                               entry = pfn_pte(__pa(p) >> PAGE_SHIFT,
+                                               PAGE_KERNEL_LARGE);
+                               set_pmd(pmd, __pmd(pte_val(entry)));
+
+                               /* check to see if we have contiguous blocks */
+                               if (p_end != p || node_start != node) {
+                                       if (p_start)
+                                               printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n",
+                                                      addr_start, addr_end-1, p_start, p_end-1, node_start);
+                                       addr_start = addr;
+                                       node_start = node;
+                                       p_start = p;
+                               }
+
+                               addr_end = addr + PMD_SIZE;
+                               p_end = p + PMD_SIZE;
+                       } else
+                               vmemmap_verify((pte_t *)pmd, node, addr, next);
                }
+
        }
        return 0;
 }
index d1b867101e5f01e74d296e52cdbd0d4801dd43e5..115f13ee40c9156fc1f954d5181b415e97c78ed3 100644 (file)
@@ -142,7 +142,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        /*
         * Don't remap the low PCI/ISA area, it's always mapped..
         */
-       if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
+       if (is_ISA_range(phys_addr, last_addr))
                return (__force void __iomem *)phys_to_virt(phys_addr);
 
        /*
@@ -261,7 +261,7 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
 {
        /*
         * Ideally, this should be:
-        *      pat_wc_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS;
+        *      pat_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS;
         *
         * Till we fix all X drivers to use ioremap_wc(), we will use
         * UC MINUS.
@@ -285,7 +285,7 @@ EXPORT_SYMBOL(ioremap_nocache);
  */
 void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size)
 {
-       if (pat_wc_enabled)
+       if (pat_enabled)
                return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WC,
                                        __builtin_return_address(0));
        else
@@ -341,8 +341,8 @@ void iounmap(volatile void __iomem *addr)
         * vm_area and by simply returning an address into the kernel mapping
         * of ISA space.   So handle that here.
         */
-       if (addr >= phys_to_virt(ISA_START_ADDRESS) &&
-           addr < phys_to_virt(ISA_END_ADDRESS))
+       if ((void __force *)addr >= phys_to_virt(ISA_START_ADDRESS) &&
+           (void __force *)addr < phys_to_virt(ISA_END_ADDRESS))
                return;
 
        addr = (volatile void __iomem *)
@@ -355,7 +355,7 @@ void iounmap(volatile void __iomem *addr)
           cpa takes care of the direct mappings. */
        read_lock(&vmlist_lock);
        for (p = vmlist; p; p = p->next) {
-               if (p->addr == addr)
+               if (p->addr == (void __force *)addr)
                        break;
        }
        read_unlock(&vmlist_lock);
@@ -369,7 +369,7 @@ void iounmap(volatile void __iomem *addr)
        free_memtype(p->phys_addr, p->phys_addr + get_vm_area_size(p));
 
        /* Finally remove it */
-       o = remove_vm_area((void *)addr);
+       o = remove_vm_area((void __force *)addr);
        BUG_ON(p != o || o == NULL);
        kfree(p);
 }
@@ -388,7 +388,7 @@ void *xlate_dev_mem_ptr(unsigned long phys)
        if (page_is_ram(start >> PAGE_SHIFT))
                return __va(phys);
 
-       addr = (void *)ioremap_default(start, PAGE_SIZE);
+       addr = (void __force *)ioremap_default(start, PAGE_SIZE);
        if (addr)
                addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
 
@@ -404,8 +404,6 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
        return;
 }
 
-#ifdef CONFIG_X86_32
-
 int __initdata early_ioremap_debug;
 
 static int __init early_ioremap_debug_setup(char *str)
@@ -417,8 +415,7 @@ static int __init early_ioremap_debug_setup(char *str)
 early_param("early_ioremap_debug", early_ioremap_debug_setup);
 
 static __initdata int after_paging_init;
-static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)]
-               __section(.bss.page_aligned);
+static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] __page_aligned_bss;
 
 static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
 {
@@ -507,10 +504,11 @@ static void __init __early_set_fixmap(enum fixed_addresses idx,
                return;
        }
        pte = early_ioremap_pte(addr);
+
        if (pgprot_val(flags))
                set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
        else
-               pte_clear(NULL, addr, pte);
+               pte_clear(&init_mm, addr, pte);
        __flush_tlb_one(addr);
 }
 
@@ -648,5 +646,3 @@ void __this_fixmap_does_not_exist(void)
 {
        WARN_ON(1);
 }
-
-#endif /* CONFIG_X86_32 */
index 1f476e477844df02d09f21ec23ddb8f5084c4cba..41f1b5c00a1d2aaffff37ba01471762a4df1de3b 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/numa.h>
 #include <asm/mpspec.h>
 #include <asm/apic.h>
+#include <asm/k8.h>
 
 static __init int find_northbridge(void)
 {
@@ -56,34 +57,33 @@ static __init void early_get_boot_cpu_id(void)
        /*
         * Find possible boot-time SMP configuration:
         */
+#ifdef CONFIG_X86_MPPARSE
        early_find_smp_config();
+#endif
 #ifdef CONFIG_ACPI
        /*
         * Read APIC information from ACPI tables.
         */
        early_acpi_boot_init();
 #endif
+#ifdef CONFIG_X86_MPPARSE
        /*
         * get boot-time SMP configuration:
         */
        if (smp_found_config)
                early_get_smp_config();
+#endif
        early_init_lapic_mapping();
 }
 
 int __init k8_scan_nodes(unsigned long start, unsigned long end)
 {
+       unsigned numnodes, cores, bits, apicid_base;
        unsigned long prevbase;
        struct bootnode nodes[8];
-       int nodeid, i, nb;
        unsigned char nodeids[8];
-       int found = 0;
-       u32 reg;
-       unsigned numnodes;
-       unsigned cores;
-       unsigned bits;
-       int j;
-       unsigned apicid_base;
+       int i, j, nb, found = 0;
+       u32 nodeid, reg;
 
        if (!early_pci_allowed())
                return -1;
@@ -105,7 +105,6 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
        prevbase = 0;
        for (i = 0; i < 8; i++) {
                unsigned long base, limit;
-               u32 nodeid;
 
                base = read_pci_config(0, nb, 1, 0x40 + i*8);
                limit = read_pci_config(0, nb, 1, 0x44 + i*8);
@@ -144,8 +143,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
                limit |= (1<<24)-1;
                limit++;
 
-               if (limit > end_pfn << PAGE_SHIFT)
-                       limit = end_pfn << PAGE_SHIFT;
+               if (limit > max_pfn << PAGE_SHIFT)
+                       limit = max_pfn << PAGE_SHIFT;
                if (limit <= base)
                        continue;
 
index c5066d519e5de4cf73dec673f6d51c2ca131075b..b432d57817737ab777ec223bfdaf3e2442f49490 100644 (file)
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
 
-bootmem_data_t plat_node_bdata[MAX_NUMNODES];
+static bootmem_data_t plat_node_bdata[MAX_NUMNODES];
 
 struct memnode memnode;
 
-#ifdef CONFIG_SMP
-int x86_cpu_to_node_map_init[NR_CPUS] = {
-       [0 ... NR_CPUS-1] = NUMA_NO_NODE
-};
-void *x86_cpu_to_node_map_early_ptr;
-EXPORT_SYMBOL(x86_cpu_to_node_map_early_ptr);
-#endif
-DEFINE_PER_CPU(int, x86_cpu_to_node_map) = NUMA_NO_NODE;
-EXPORT_PER_CPU_SYMBOL(x86_cpu_to_node_map);
-
 s16 apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
        [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
 };
 
-cpumask_t node_to_cpumask_map[MAX_NUMNODES] __read_mostly;
-EXPORT_SYMBOL(node_to_cpumask_map);
-
 int numa_off __initdata;
-unsigned long __initdata nodemap_addr;
-unsigned long __initdata nodemap_size;
+static unsigned long __initdata nodemap_addr;
+static unsigned long __initdata nodemap_size;
 
 /*
  * Given a shift value, try to populate memnodemap[]
@@ -99,7 +86,7 @@ static int __init allocate_cachealigned_memnodemap(void)
 
        addr = 0x8000;
        nodemap_size = round_up(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
-       nodemap_addr = find_e820_area(addr, end_pfn<<PAGE_SHIFT,
+       nodemap_addr = find_e820_area(addr, max_pfn<<PAGE_SHIFT,
                                      nodemap_size, L1_CACHE_BYTES);
        if (nodemap_addr == -1UL) {
                printk(KERN_ERR
@@ -192,7 +179,7 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
 void __init setup_node_bootmem(int nodeid, unsigned long start,
                               unsigned long end)
 {
-       unsigned long start_pfn, end_pfn, bootmap_pages, bootmap_size;
+       unsigned long start_pfn, last_pfn, bootmap_pages, bootmap_size;
        unsigned long bootmap_start, nodedata_phys;
        void *bootmap;
        const int pgdat_size = round_up(sizeof(pg_data_t), PAGE_SIZE);
@@ -204,7 +191,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
               start, end);
 
        start_pfn = start >> PAGE_SHIFT;
-       end_pfn = end >> PAGE_SHIFT;
+       last_pfn = end >> PAGE_SHIFT;
 
        node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size,
                                           SMP_CACHE_BYTES);
@@ -217,7 +204,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
        memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
        NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid];
        NODE_DATA(nodeid)->node_start_pfn = start_pfn;
-       NODE_DATA(nodeid)->node_spanned_pages = end_pfn - start_pfn;
+       NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn;
 
        /*
         * Find a place for the bootmem map
@@ -226,14 +213,14 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
         * early_node_mem will get that with find_e820_area instead
         * of alloc_bootmem, that could clash with reserved range
         */
-       bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
+       bootmap_pages = bootmem_bootmap_pages(last_pfn - start_pfn);
        nid = phys_to_nid(nodedata_phys);
        if (nid == nodeid)
                bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
        else
                bootmap_start = round_up(start, PAGE_SIZE);
        /*
-        * SMP_CAHCE_BYTES could be enough, but init_bootmem_node like
+        * SMP_CACHE_BYTES could be enough, but init_bootmem_node like
         * to use that to align to PAGE_SIZE
         */
        bootmap = early_node_mem(nodeid, bootmap_start, end,
@@ -248,7 +235,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
 
        bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
                                         bootmap_start >> PAGE_SHIFT,
-                                        start_pfn, end_pfn);
+                                        start_pfn, last_pfn);
 
        printk(KERN_INFO "  bootmap [%016lx -  %016lx] pages %lx\n",
                 bootmap_start, bootmap_start + bootmap_size - 1,
@@ -309,7 +296,7 @@ void __init numa_init_array(void)
 
 #ifdef CONFIG_NUMA_EMU
 /* Numa emulation */
-char *cmdline __initdata;
+static char *cmdline __initdata;
 
 /*
  * Setups up nid to range from addr to addr + size.  If the end
@@ -413,15 +400,15 @@ static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
 }
 
 /*
- * Sets up the system RAM area from start_pfn to end_pfn according to the
+ * Sets up the system RAM area from start_pfn to last_pfn according to the
  * numa=fake command-line option.
  */
 static struct bootnode nodes[MAX_NUMNODES] __initdata;
 
-static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn)
 {
        u64 size, addr = start_pfn << PAGE_SHIFT;
-       u64 max_addr = end_pfn << PAGE_SHIFT;
+       u64 max_addr = last_pfn << PAGE_SHIFT;
        int num_nodes = 0, num = 0, coeff_flag, coeff = -1, i;
 
        memset(&nodes, 0, sizeof(nodes));
@@ -527,7 +514,7 @@ out:
 }
 #endif /* CONFIG_NUMA_EMU */
 
-void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn)
 {
        int i;
 
@@ -535,7 +522,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
        nodes_clear(node_online_map);
 
 #ifdef CONFIG_NUMA_EMU
-       if (cmdline && !numa_emulation(start_pfn, end_pfn))
+       if (cmdline && !numa_emulation(start_pfn, last_pfn))
                return;
        nodes_clear(node_possible_map);
        nodes_clear(node_online_map);
@@ -543,7 +530,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
 
 #ifdef CONFIG_ACPI_NUMA
        if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
-                                         end_pfn << PAGE_SHIFT))
+                                         last_pfn << PAGE_SHIFT))
                return;
        nodes_clear(node_possible_map);
        nodes_clear(node_online_map);
@@ -551,7 +538,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
 
 #ifdef CONFIG_K8_NUMA
        if (!numa_off && !k8_scan_nodes(start_pfn<<PAGE_SHIFT,
-                                       end_pfn<<PAGE_SHIFT))
+                                       last_pfn<<PAGE_SHIFT))
                return;
        nodes_clear(node_possible_map);
        nodes_clear(node_online_map);
@@ -561,7 +548,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
 
        printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
               start_pfn << PAGE_SHIFT,
-              end_pfn << PAGE_SHIFT);
+              last_pfn << PAGE_SHIFT);
        /* setup dummy node covering all memory */
        memnode_shift = 63;
        memnodemap = memnode.embedded_map;
@@ -570,29 +557,8 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
        node_set(0, node_possible_map);
        for (i = 0; i < NR_CPUS; i++)
                numa_set_node(i, 0);
-       /* cpumask_of_cpu() may not be available during early startup */
-       memset(&node_to_cpumask_map[0], 0, sizeof(node_to_cpumask_map[0]));
-       cpu_set(0, node_to_cpumask_map[0]);
-       e820_register_active_regions(0, start_pfn, end_pfn);
-       setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
-}
-
-__cpuinit void numa_add_cpu(int cpu)
-{
-       set_bit(cpu,
-               (unsigned long *)&node_to_cpumask_map[early_cpu_to_node(cpu)]);
-}
-
-void __cpuinit numa_set_node(int cpu, int node)
-{
-       int *cpu_to_node_map = x86_cpu_to_node_map_early_ptr;
-
-       if(cpu_to_node_map)
-               cpu_to_node_map[cpu] = node;
-       else if(per_cpu_offset(cpu))
-               per_cpu(x86_cpu_to_node_map, cpu) = node;
-       else
-               Dprintk(KERN_INFO "Setting node for non-present cpu %d\n", cpu);
+       e820_register_active_regions(0, start_pfn, last_pfn);
+       setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
 }
 
 unsigned long __init numa_free_all_bootmem(void)
@@ -613,7 +579,7 @@ void __init paging_init(void)
        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] = end_pfn;
+       max_zone_pfns[ZONE_NORMAL] = max_pfn;
 
        sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
@@ -641,6 +607,7 @@ static __init int numa_setup(char *opt)
 }
 early_param("numa", numa_setup);
 
+#ifdef CONFIG_NUMA
 /*
  * Setup early cpu_to_node.
  *
@@ -652,14 +619,19 @@ early_param("numa", numa_setup);
  * is already initialized in a round robin manner at numa_init_array,
  * prior to this call, and this initialization is good enough
  * for the fake NUMA cases.
+ *
+ * Called before the per_cpu areas are setup.
  */
 void __init init_cpu_to_node(void)
 {
-       int i;
+       int cpu;
+       u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
 
-       for (i = 0; i < NR_CPUS; i++) {
+       BUG_ON(cpu_to_apicid == NULL);
+
+       for_each_possible_cpu(cpu) {
                int node;
-               u16 apicid = x86_cpu_to_apicid_init[i];
+               u16 apicid = cpu_to_apicid[cpu];
 
                if (apicid == BAD_APICID)
                        continue;
@@ -668,8 +640,9 @@ void __init init_cpu_to_node(void)
                        continue;
                if (!node_online(node))
                        continue;
-               numa_set_node(i, node);
+               numa_set_node(cpu, node);
        }
 }
+#endif
 
 
index 75f1b109aae8fe6711d12b440df3743f38150ce3..0dcd42eb94e66fd8650422cb25e348cc18da3cf5 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * self test for change_page_attr.
  *
- * Clears the global bit on random pages in the direct mapping, then reverts
- * and compares page tables forwards and afterwards.
+ * Clears the a test pte bit on random pages in the direct mapping,
+ * then reverts and compares page tables forwards and afterwards.
  */
 #include <linux/bootmem.h>
 #include <linux/kthread.h>
@@ -32,6 +32,13 @@ enum {
        GPS                     = (1<<30)
 };
 
+#define PAGE_TESTBIT   __pgprot(_PAGE_UNUSED1)
+
+static int pte_testbit(pte_t pte)
+{
+       return pte_flags(pte) & _PAGE_UNUSED1;
+}
+
 struct split_state {
        long lpg, gpg, spg, exec;
        long min_exec, max_exec;
@@ -165,15 +172,14 @@ static int pageattr_test(void)
                        continue;
                }
 
-               err = change_page_attr_clear(addr[i], len[i],
-                                              __pgprot(_PAGE_GLOBAL));
+               err = change_page_attr_set(addr[i], len[i], PAGE_TESTBIT);
                if (err < 0) {
                        printk(KERN_ERR "CPA %d failed %d\n", i, err);
                        failed++;
                }
 
                pte = lookup_address(addr[i], &level);
-               if (!pte || pte_global(*pte) || pte_huge(*pte)) {
+               if (!pte || !pte_testbit(*pte) || pte_huge(*pte)) {
                        printk(KERN_ERR "CPA %lx: bad pte %Lx\n", addr[i],
                                pte ? (u64)pte_val(*pte) : 0ULL);
                        failed++;
@@ -198,14 +204,13 @@ static int pageattr_test(void)
                        failed++;
                        continue;
                }
-               err = change_page_attr_set(addr[i], len[i],
-                                            __pgprot(_PAGE_GLOBAL));
+               err = change_page_attr_clear(addr[i], len[i], PAGE_TESTBIT);
                if (err < 0) {
                        printk(KERN_ERR "CPA reverting failed: %d\n", err);
                        failed++;
                }
                pte = lookup_address(addr[i], &level);
-               if (!pte || !pte_global(*pte)) {
+               if (!pte || pte_testbit(*pte)) {
                        printk(KERN_ERR "CPA %lx: bad pte after revert %Lx\n",
                                addr[i], pte ? (u64)pte_val(*pte) : 0ULL);
                        failed++;
index 60bcb5b6a37ef0130fb08da8ef38db58fd37910a..fb6f2ab40dda092f5029b1e29542fb2d9accb6f7 100644 (file)
@@ -34,6 +34,41 @@ struct cpa_data {
        unsigned        force_split : 1;
 };
 
+#ifdef CONFIG_PROC_FS
+static unsigned long direct_pages_count[PG_LEVEL_NUM];
+
+void update_page_count(int level, unsigned long pages)
+{
+       unsigned long flags;
+
+       /* Protect against CPA */
+       spin_lock_irqsave(&pgd_lock, flags);
+       direct_pages_count[level] += pages;
+       spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
+static void split_page_count(int level)
+{
+       direct_pages_count[level]--;
+       direct_pages_count[level - 1] += PTRS_PER_PTE;
+}
+
+int arch_report_meminfo(char *page)
+{
+       int n = sprintf(page, "DirectMap4k:  %8lu\n"
+                       "DirectMap2M:  %8lu\n",
+                       direct_pages_count[PG_LEVEL_4K],
+                       direct_pages_count[PG_LEVEL_2M]);
+#ifdef CONFIG_X86_64
+       n += sprintf(page + n, "DirectMap1G:  %8lu\n",
+                    direct_pages_count[PG_LEVEL_1G]);
+#endif
+       return n;
+}
+#else
+static inline void split_page_count(int level) { }
+#endif
+
 #ifdef CONFIG_X86_64
 
 static inline unsigned long highmap_start_pfn(void)
@@ -500,6 +535,16 @@ static int split_large_page(pte_t *kpte, unsigned long address)
        for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
                set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
 
+       if (address >= (unsigned long)__va(0) &&
+               address < (unsigned long)__va(max_low_pfn_mapped << PAGE_SHIFT))
+               split_page_count(level);
+
+#ifdef CONFIG_X86_64
+       if (address >= (unsigned long)__va(1UL<<32) &&
+               address < (unsigned long)__va(max_pfn_mapped << PAGE_SHIFT))
+               split_page_count(level);
+#endif
+
        /*
         * Install the new, split up pagetable. Important details here:
         *
@@ -613,15 +658,24 @@ static int cpa_process_alias(struct cpa_data *cpa)
        struct cpa_data alias_cpa;
        int ret = 0;
 
-       if (cpa->pfn > max_pfn_mapped)
+       if (cpa->pfn >= max_pfn_mapped)
                return 0;
 
+#ifdef CONFIG_X86_64
+       if (cpa->pfn >= max_low_pfn_mapped && cpa->pfn < (1UL<<(32-PAGE_SHIFT)))
+               return 0;
+#endif
        /*
         * No need to redo, when the primary call touched the direct
         * mapping already:
         */
-       if (!within(cpa->vaddr, PAGE_OFFSET,
-                   PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))) {
+       if (!(within(cpa->vaddr, PAGE_OFFSET,
+                   PAGE_OFFSET + (max_low_pfn_mapped << PAGE_SHIFT))
+#ifdef CONFIG_X86_64
+               || within(cpa->vaddr, PAGE_OFFSET + (1UL<<32),
+                   PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))
+#endif
+       )) {
 
                alias_cpa = *cpa;
                alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
@@ -805,7 +859,7 @@ int _set_memory_wc(unsigned long addr, int numpages)
 
 int set_memory_wc(unsigned long addr, int numpages)
 {
-       if (!pat_wc_enabled)
+       if (!pat_enabled)
                return set_memory_uc(addr, numpages);
 
        if (reserve_memtype(addr, addr + numpages * PAGE_SIZE,
index 06b7a1c90fb89e43eadd396592cbf6625080020b..d4585077977a0bd1c6c7234b09051d671851a6aa 100644 (file)
 #include <asm/io.h>
 
 #ifdef CONFIG_X86_PAT
-int __read_mostly pat_wc_enabled = 1;
+int __read_mostly pat_enabled = 1;
 
 void __cpuinit pat_disable(char *reason)
 {
-       pat_wc_enabled = 0;
+       pat_enabled = 0;
        printk(KERN_INFO "%s\n", reason);
 }
 
@@ -42,6 +42,19 @@ static int __init nopat(char *str)
 early_param("nopat", nopat);
 #endif
 
+
+static int debug_enable;
+static int __init pat_debug_setup(char *str)
+{
+       debug_enable = 1;
+       return 0;
+}
+__setup("debugpat", pat_debug_setup);
+
+#define dprintk(fmt, arg...) \
+       do { if (debug_enable) printk(KERN_INFO fmt, ##arg); } while (0)
+
+
 static u64 __read_mostly boot_pat_state;
 
 enum {
@@ -53,24 +66,25 @@ enum {
        PAT_UC_MINUS = 7,       /* UC, but can be overriden by MTRR */
 };
 
-#define PAT(x,y)       ((u64)PAT_ ## y << ((x)*8))
+#define PAT(x, y)      ((u64)PAT_ ## y << ((x)*8))
 
 void pat_init(void)
 {
        u64 pat;
 
-       if (!pat_wc_enabled)
+       if (!pat_enabled)
                return;
 
        /* Paranoia check. */
-       if (!cpu_has_pat) {
-               printk(KERN_ERR "PAT enabled, but CPU feature cleared\n");
+       if (!cpu_has_pat && boot_pat_state) {
                /*
-                * Panic if this happens on the secondary CPU, and we
+                * If this happens we are on a secondary CPU, but
                 * switched to PAT on the boot CPU. We have no way to
                 * undo PAT.
-               */
-               BUG_ON(boot_pat_state);
+                */
+               printk(KERN_ERR "PAT enabled, "
+                      "but not supported by secondary CPU\n");
+               BUG();
        }
 
        /* Set PWT to Write-Combining. All other bits stay the same */
@@ -86,8 +100,8 @@ void pat_init(void)
         *      011 UC          _PAGE_CACHE_UC
         * PAT bit unused
         */
-       pat = PAT(0,WB) | PAT(1,WC) | PAT(2,UC_MINUS) | PAT(3,UC) |
-             PAT(4,WB) | PAT(5,WC) | PAT(6,UC_MINUS) | PAT(7,UC);
+       pat = PAT(0, WB) | PAT(1, WC) | PAT(2, UC_MINUS) | PAT(3, UC) |
+             PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC);
 
        /* Boot CPU check */
        if (!boot_pat_state)
@@ -103,11 +117,11 @@ void pat_init(void)
 static char *cattr_name(unsigned long flags)
 {
        switch (flags & _PAGE_CACHE_MASK) {
-               case _PAGE_CACHE_UC:            return "uncached";
-               case _PAGE_CACHE_UC_MINUS:      return "uncached-minus";
-               case _PAGE_CACHE_WB:            return "write-back";
-               case _PAGE_CACHE_WC:            return "write-combining";
-               default:                        return "broken";
+       case _PAGE_CACHE_UC:            return "uncached";
+       case _PAGE_CACHE_UC_MINUS:      return "uncached-minus";
+       case _PAGE_CACHE_WB:            return "write-back";
+       case _PAGE_CACHE_WC:            return "write-combining";
+       default:                        return "broken";
        }
 }
 
@@ -145,47 +159,50 @@ static DEFINE_SPINLOCK(memtype_lock);     /* protects memtype list */
  * The intersection is based on "Effective Memory Type" tables in IA-32
  * SDM vol 3a
  */
-static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot,
-                               unsigned long *ret_prot)
+static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type)
 {
-       unsigned long pat_type;
-       u8 mtrr_type;
-
-       pat_type = prot & _PAGE_CACHE_MASK;
-       prot &= (~_PAGE_CACHE_MASK);
-
-       /*
-        * We return the PAT request directly for types where PAT takes
-        * precedence with respect to MTRR and for UC_MINUS.
-        * Consistency checks with other PAT requests is done later
-        * while going through memtype list.
-        */
-       if (pat_type == _PAGE_CACHE_WC) {
-               *ret_prot = prot | _PAGE_CACHE_WC;
-               return 0;
-       } else if (pat_type == _PAGE_CACHE_UC_MINUS) {
-               *ret_prot = prot | _PAGE_CACHE_UC_MINUS;
-               return 0;
-       } else if (pat_type == _PAGE_CACHE_UC) {
-               *ret_prot = prot | _PAGE_CACHE_UC;
-               return 0;
-       }
-
        /*
         * Look for MTRR hint to get the effective type in case where PAT
         * request is for WB.
         */
-       mtrr_type = mtrr_type_lookup(start, end);
+       if (req_type == _PAGE_CACHE_WB) {
+               u8 mtrr_type;
+
+               mtrr_type = mtrr_type_lookup(start, end);
+               if (mtrr_type == MTRR_TYPE_UNCACHABLE)
+                       return _PAGE_CACHE_UC;
+               if (mtrr_type == MTRR_TYPE_WRCOMB)
+                       return _PAGE_CACHE_WC;
+       }
 
-       if (mtrr_type == MTRR_TYPE_UNCACHABLE) {
-               *ret_prot = prot | _PAGE_CACHE_UC;
-       } else if (mtrr_type == MTRR_TYPE_WRCOMB) {
-               *ret_prot = prot | _PAGE_CACHE_WC;
-       } else {
-               *ret_prot = prot | _PAGE_CACHE_WB;
+       return req_type;
+}
+
+static int chk_conflict(struct memtype *new, struct memtype *entry,
+                       unsigned long *type)
+{
+       if (new->type != entry->type) {
+               if (type) {
+                       new->type = entry->type;
+                       *type = entry->type;
+               } else
+                       goto conflict;
        }
 
+        /* check overlaps with more than one entry in the list */
+       list_for_each_entry_continue(entry, &memtype_list, nd) {
+               if (new->end <= entry->start)
+                       break;
+               else if (new->type != entry->type)
+                       goto conflict;
+       }
        return 0;
+
+ conflict:
+       printk(KERN_INFO "%s:%d conflicting memory types "
+              "%Lx-%Lx %s<->%s\n", current->comm, current->pid, new->start,
+              new->end, cattr_name(new->type), cattr_name(entry->type));
+       return -EBUSY;
 }
 
 /*
@@ -198,37 +215,36 @@ static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot,
  * req_type will have a special case value '-1', when requester want to inherit
  * the memory type from mtrr (if WB), existing PAT, defaulting to UC_MINUS.
  *
- * If ret_type is NULL, function will return an error if it cannot reserve the
- * region with req_type. If ret_type is non-null, function will return
- * available type in ret_type in case of no error. In case of any error
+ * If new_type is NULL, function will return an error if it cannot reserve the
+ * region with req_type. If new_type is non-NULL, function will return
+ * available type in new_type in case of no error. In case of any error
  * it will return a negative return value.
  */
 int reserve_memtype(u64 start, u64 end, unsigned long req_type,
-                       unsigned long *ret_type)
+                       unsigned long *new_type)
 {
-       struct memtype *new_entry = NULL;
-       struct memtype *parse;
+       struct memtype *new, *entry;
        unsigned long actual_type;
+       struct list_head *where;
        int err = 0;
 
-       /* Only track when pat_wc_enabled */
-       if (!pat_wc_enabled) {
+       BUG_ON(start >= end); /* end is exclusive */
+
+       if (!pat_enabled) {
                /* This is identical to page table setting without PAT */
-               if (ret_type) {
-                       if (req_type == -1) {
-                               *ret_type = _PAGE_CACHE_WB;
-                       } else {
-                               *ret_type = req_type;
-                       }
+               if (new_type) {
+                       if (req_type == -1)
+                               *new_type = _PAGE_CACHE_WB;
+                       else
+                               *new_type = req_type & _PAGE_CACHE_MASK;
                }
                return 0;
        }
 
        /* Low ISA region is always mapped WB in page table. No need to track */
-       if (start >= ISA_START_ADDRESS && (end - 1) <= ISA_END_ADDRESS) {
-               if (ret_type)
-                       *ret_type = _PAGE_CACHE_WB;
-
+       if (is_ISA_range(start, end - 1)) {
+               if (new_type)
+                       *new_type = _PAGE_CACHE_WB;
                return 0;
        }
 
@@ -241,206 +257,92 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
                 */
                u8 mtrr_type = mtrr_type_lookup(start, end);
 
-               if (mtrr_type == MTRR_TYPE_WRBACK) {
-                       req_type = _PAGE_CACHE_WB;
+               if (mtrr_type == MTRR_TYPE_WRBACK)
                        actual_type = _PAGE_CACHE_WB;
-               } else {
-                       req_type = _PAGE_CACHE_UC_MINUS;
+               else
                        actual_type = _PAGE_CACHE_UC_MINUS;
-               }
-       } else {
-               req_type &= _PAGE_CACHE_MASK;
-               err = pat_x_mtrr_type(start, end, req_type, &actual_type);
-       }
-
-       if (err) {
-               if (ret_type)
-                       *ret_type = actual_type;
-
-               return -EINVAL;
-       }
+       } else
+               actual_type = pat_x_mtrr_type(start, end,
+                                             req_type & _PAGE_CACHE_MASK);
 
-       new_entry  = kmalloc(sizeof(struct memtype), GFP_KERNEL);
-       if (!new_entry)
+       new  = kmalloc(sizeof(struct memtype), GFP_KERNEL);
+       if (!new)
                return -ENOMEM;
 
-       new_entry->start = start;
-       new_entry->end = end;
-       new_entry->type = actual_type;
+       new->start = start;
+       new->end = end;
+       new->type = actual_type;
 
-       if (ret_type)
-               *ret_type = actual_type;
+       if (new_type)
+               *new_type = actual_type;
 
        spin_lock(&memtype_lock);
 
        /* Search for existing mapping that overlaps the current range */
-       list_for_each_entry(parse, &memtype_list, nd) {
-               struct memtype *saved_ptr;
-
-               if (parse->start >= end) {
-                       pr_debug("New Entry\n");
-                       list_add(&new_entry->nd, parse->nd.prev);
-                       new_entry = NULL;
+       where = NULL;
+       list_for_each_entry(entry, &memtype_list, nd) {
+               if (end <= entry->start) {
+                       where = entry->nd.prev;
                        break;
-               }
-
-               if (start <= parse->start && end >= parse->start) {
-                       if (actual_type != parse->type && ret_type) {
-                               actual_type = parse->type;
-                               *ret_type = actual_type;
-                               new_entry->type = actual_type;
-                       }
-
-                       if (actual_type != parse->type) {
-                               printk(
-               KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
-                                       current->comm, current->pid,
-                                       start, end,
-                                       cattr_name(actual_type),
-                                       cattr_name(parse->type));
-                               err = -EBUSY;
-                               break;
+               } else if (start <= entry->start) { /* end > entry->start */
+                       err = chk_conflict(new, entry, new_type);
+                       if (!err) {
+                               dprintk("Overlap at 0x%Lx-0x%Lx\n",
+                                       entry->start, entry->end);
+                               where = entry->nd.prev;
                        }
-
-                       saved_ptr = parse;
-                       /*
-                        * Check to see whether the request overlaps more
-                        * than one entry in the list
-                        */
-                       list_for_each_entry_continue(parse, &memtype_list, nd) {
-                               if (end <= parse->start) {
-                                       break;
-                               }
-
-                               if (actual_type != parse->type) {
-                                       printk(
-               KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
-                                               current->comm, current->pid,
-                                               start, end,
-                                               cattr_name(actual_type),
-                                               cattr_name(parse->type));
-                                       err = -EBUSY;
-                                       break;
-                               }
-                       }
-
-                       if (err) {
-                               break;
-                       }
-
-                       pr_debug("Overlap at 0x%Lx-0x%Lx\n",
-                              saved_ptr->start, saved_ptr->end);
-                       /* No conflict. Go ahead and add this new entry */
-                       list_add(&new_entry->nd, saved_ptr->nd.prev);
-                       new_entry = NULL;
                        break;
-               }
-
-               if (start < parse->end) {
-                       if (actual_type != parse->type && ret_type) {
-                               actual_type = parse->type;
-                               *ret_type = actual_type;
-                               new_entry->type = actual_type;
-                       }
-
-                       if (actual_type != parse->type) {
-                               printk(
-               KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
-                                       current->comm, current->pid,
-                                       start, end,
-                                       cattr_name(actual_type),
-                                       cattr_name(parse->type));
-                               err = -EBUSY;
-                               break;
-                       }
-
-                       saved_ptr = parse;
-                       /*
-                        * Check to see whether the request overlaps more
-                        * than one entry in the list
-                        */
-                       list_for_each_entry_continue(parse, &memtype_list, nd) {
-                               if (end <= parse->start) {
-                                       break;
-                               }
-
-                               if (actual_type != parse->type) {
-                                       printk(
-               KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n",
-                                               current->comm, current->pid,
-                                               start, end,
-                                               cattr_name(actual_type),
-                                               cattr_name(parse->type));
-                                       err = -EBUSY;
-                                       break;
-                               }
-                       }
-
-                       if (err) {
-                               break;
+               } else if (start < entry->end) { /* start > entry->start */
+                       err = chk_conflict(new, entry, new_type);
+                       if (!err) {
+                               dprintk("Overlap at 0x%Lx-0x%Lx\n",
+                                       entry->start, entry->end);
+                               where = &entry->nd;
                        }
-
-                       pr_debug(KERN_INFO "Overlap at 0x%Lx-0x%Lx\n",
-                                saved_ptr->start, saved_ptr->end);
-                       /* No conflict. Go ahead and add this new entry */
-                       list_add(&new_entry->nd, &saved_ptr->nd);
-                       new_entry = NULL;
                        break;
                }
        }
 
        if (err) {
-               printk(KERN_INFO
-       "reserve_memtype failed 0x%Lx-0x%Lx, track %s, req %s\n",
-                       start, end, cattr_name(new_entry->type),
-                       cattr_name(req_type));
-               kfree(new_entry);
+               printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, "
+                      "track %s, req %s\n",
+                      start, end, cattr_name(new->type), cattr_name(req_type));
+               kfree(new);
                spin_unlock(&memtype_lock);
                return err;
        }
 
-       if (new_entry) {
-               /* No conflict. Not yet added to the list. Add to the tail */
-               list_add_tail(&new_entry->nd, &memtype_list);
-               pr_debug("New Entry\n");
-       }
-
-       if (ret_type) {
-               pr_debug(
-       "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n",
-                       start, end, cattr_name(actual_type),
-                       cattr_name(req_type), cattr_name(*ret_type));
-       } else {
-               pr_debug(
-       "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s\n",
-                       start, end, cattr_name(actual_type),
-                       cattr_name(req_type));
-       }
+       if (where)
+               list_add(&new->nd, where);
+       else
+               list_add_tail(&new->nd, &memtype_list);
 
        spin_unlock(&memtype_lock);
+
+       dprintk("reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n",
+               start, end, cattr_name(new->type), cattr_name(req_type),
+               new_type ? cattr_name(*new_type) : "-");
+
        return err;
 }
 
 int free_memtype(u64 start, u64 end)
 {
-       struct memtype *ml;
+       struct memtype *entry;
        int err = -EINVAL;
 
-       /* Only track when pat_wc_enabled */
-       if (!pat_wc_enabled) {
+       if (!pat_enabled)
                return 0;
-       }
 
        /* Low ISA region is always mapped WB. No need to track */
-       if (start >= ISA_START_ADDRESS && end <= ISA_END_ADDRESS) {
+       if (is_ISA_range(start, end - 1))
                return 0;
-       }
 
        spin_lock(&memtype_lock);
-       list_for_each_entry(ml, &memtype_list, nd) {
-               if (ml->start == start && ml->end == end) {
-                       list_del(&ml->nd);
-                       kfree(ml);
+       list_for_each_entry(entry, &memtype_list, nd) {
+               if (entry->start == start && entry->end == end) {
+                       list_del(&entry->nd);
+                       kfree(entry);
                        err = 0;
                        break;
                }
@@ -452,7 +354,7 @@ int free_memtype(u64 start, u64 end)
                        current->comm, current->pid, start, end);
        }
 
-       pr_debug("free_memtype request 0x%Lx-0x%Lx\n", start, end);
+       dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end);
        return err;
 }
 
@@ -521,12 +423,12 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
         * caching for the high addresses through the KEN pin, but
         * we maintain the tradition of paranoia in this code.
         */
-       if (!pat_wc_enabled &&
-           ! ( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) ||
-               test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) ||
-               test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ||
-               test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability)) &&
-          (pfn << PAGE_SHIFT) >= __pa(high_memory)) {
+       if (!pat_enabled &&
+           !(boot_cpu_has(X86_FEATURE_MTRR) ||
+             boot_cpu_has(X86_FEATURE_K6_MTRR) ||
+             boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
+             boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) &&
+           (pfn << PAGE_SHIFT) >= __pa(high_memory)) {
                flags = _PAGE_CACHE_UC;
        }
 #endif
@@ -547,8 +449,9 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
        if (retval < 0)
                return 0;
 
-       if (pfn <= max_pfn_mapped &&
-            ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) {
+       if (((pfn < max_low_pfn_mapped) ||
+            (pfn >= (1UL<<(32 - PAGE_SHIFT)) && pfn < max_pfn_mapped)) &&
+           ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) {
                free_memtype(offset, offset + size);
                printk(KERN_INFO
                "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n",
@@ -586,4 +489,3 @@ void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
 
        free_memtype(addr, addr + size);
 }
-
index 50159764f694e91dc0b9a3884290d52233219953..557b2abceef86f83058ff447be17a1da56942d44 100644 (file)
@@ -2,6 +2,7 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/tlb.h>
+#include <asm/fixmap.h>
 
 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
@@ -65,12 +66,6 @@ static inline void pgd_list_del(pgd_t *pgd)
 static void pgd_ctor(void *p)
 {
        pgd_t *pgd = p;
-       unsigned long flags;
-
-       /* Clear usermode parts of PGD */
-       memset(pgd, 0, KERNEL_PGD_BOUNDARY*sizeof(pgd_t));
-
-       spin_lock_irqsave(&pgd_lock, flags);
 
        /* If the pgd points to a shared pagetable level (either the
           ptes in non-PAE, or shared PMD in PAE), then just copy the
@@ -90,8 +85,6 @@ static void pgd_ctor(void *p)
        /* list required to sync kernel mapping updates */
        if (!SHARED_KERNEL_PMD)
                pgd_list_add(pgd);
-
-       spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
 static void pgd_dtor(void *pgd)
@@ -118,6 +111,72 @@ static void pgd_dtor(void *pgd)
  */
 
 #ifdef CONFIG_X86_PAE
+/*
+ * In PAE mode, we need to do a cr3 reload (=tlb flush) when
+ * updating the top-level pagetable entries to guarantee the
+ * processor notices the update.  Since this is expensive, and
+ * all 4 top-level entries are used almost immediately in a
+ * new process's life, we just pre-populate them here.
+ *
+ * Also, if we're in a paravirt environment where the kernel pmd is
+ * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate
+ * and initialize the kernel pmds here.
+ */
+#define PREALLOCATED_PMDS      UNSHARED_PTRS_PER_PGD
+
+void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
+{
+       paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT);
+
+       /* Note: almost everything apart from _PAGE_PRESENT is
+          reserved at the pmd (PDPT) level. */
+       set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
+
+       /*
+        * According to Intel App note "TLBs, Paging-Structure Caches,
+        * and Their Invalidation", April 2007, document 317080-001,
+        * section 8.1: in PAE mode we explicitly have to flush the
+        * TLB via cr3 if the top-level pgd is changed...
+        */
+       if (mm == current->active_mm)
+               write_cr3(read_cr3());
+}
+#else  /* !CONFIG_X86_PAE */
+
+/* No need to prepopulate any pagetable entries in non-PAE modes. */
+#define PREALLOCATED_PMDS      0
+
+#endif /* CONFIG_X86_PAE */
+
+static void free_pmds(pmd_t *pmds[])
+{
+       int i;
+
+       for(i = 0; i < PREALLOCATED_PMDS; i++)
+               if (pmds[i])
+                       free_page((unsigned long)pmds[i]);
+}
+
+static int preallocate_pmds(pmd_t *pmds[])
+{
+       int i;
+       bool failed = false;
+
+       for(i = 0; i < PREALLOCATED_PMDS; i++) {
+               pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+               if (pmd == NULL)
+                       failed = true;
+               pmds[i] = pmd;
+       }
+
+       if (failed) {
+               free_pmds(pmds);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 /*
  * Mop up any pmd pages which may still be attached to the pgd.
  * Normally they will be freed by munmap/exit_mmap, but any pmd we
@@ -128,7 +187,7 @@ static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
 {
        int i;
 
-       for(i = 0; i < UNSHARED_PTRS_PER_PGD; i++) {
+       for(i = 0; i < PREALLOCATED_PMDS; i++) {
                pgd_t pgd = pgdp[i];
 
                if (pgd_val(pgd) != 0) {
@@ -142,32 +201,17 @@ static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
        }
 }
 
-/*
- * In PAE mode, we need to do a cr3 reload (=tlb flush) when
- * updating the top-level pagetable entries to guarantee the
- * processor notices the update.  Since this is expensive, and
- * all 4 top-level entries are used almost immediately in a
- * new process's life, we just pre-populate them here.
- *
- * Also, if we're in a paravirt environment where the kernel pmd is
- * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate
- * and initialize the kernel pmds here.
- */
-static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
+static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[])
 {
        pud_t *pud;
        unsigned long addr;
        int i;
 
        pud = pud_offset(pgd, 0);
-       for (addr = i = 0; i < UNSHARED_PTRS_PER_PGD;
-            i++, pud++, addr += PUD_SIZE) {
-               pmd_t *pmd = pmd_alloc_one(mm, addr);
 
-               if (!pmd) {
-                       pgd_mop_up_pmds(mm, pgd);
-                       return 0;
-               }
+       for (addr = i = 0; i < PREALLOCATED_PMDS;
+            i++, pud++, addr += PUD_SIZE) {
+               pmd_t *pmd = pmds[i];
 
                if (i >= KERNEL_PGD_BOUNDARY)
                        memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]),
@@ -175,61 +219,54 @@ static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
 
                pud_populate(mm, pud, pmd);
        }
-
-       return 1;
 }
 
-void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
+pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT);
+       pgd_t *pgd;
+       pmd_t *pmds[PREALLOCATED_PMDS];
+       unsigned long flags;
 
-       /* Note: almost everything apart from _PAGE_PRESENT is
-          reserved at the pmd (PDPT) level. */
-       set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
+       pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
 
-       /*
-        * According to Intel App note "TLBs, Paging-Structure Caches,
-        * and Their Invalidation", April 2007, document 317080-001,
-        * section 8.1: in PAE mode we explicitly have to flush the
-        * TLB via cr3 if the top-level pgd is changed...
-        */
-       if (mm == current->active_mm)
-               write_cr3(read_cr3());
-}
-#else  /* !CONFIG_X86_PAE */
-/* No need to prepopulate any pagetable entries in non-PAE modes. */
-static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
-{
-       return 1;
-}
+       if (pgd == NULL)
+               goto out;
 
-static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgd)
-{
-}
-#endif /* CONFIG_X86_PAE */
+       mm->pgd = pgd;
 
-pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-       pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+       if (preallocate_pmds(pmds) != 0)
+               goto out_free_pgd;
 
-       /* so that alloc_pmd can use it */
-       mm->pgd = pgd;
-       if (pgd)
-               pgd_ctor(pgd);
+       if (paravirt_pgd_alloc(mm) != 0)
+               goto out_free_pmds;
 
-       if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
-               pgd_dtor(pgd);
-               free_page((unsigned long)pgd);
-               pgd = NULL;
-       }
+       /*
+        * Make sure that pre-populating the pmds is atomic with
+        * respect to anything walking the pgd_list, so that they
+        * never see a partially populated pgd.
+        */
+       spin_lock_irqsave(&pgd_lock, flags);
+
+       pgd_ctor(pgd);
+       pgd_prepopulate_pmd(mm, pgd, pmds);
+
+       spin_unlock_irqrestore(&pgd_lock, flags);
 
        return pgd;
+
+out_free_pmds:
+       free_pmds(pmds);
+out_free_pgd:
+       free_page((unsigned long)pgd);
+out:
+       return NULL;
 }
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        pgd_mop_up_pmds(mm, pgd);
        pgd_dtor(pgd);
+       paravirt_pgd_free(mm, pgd);
        free_page((unsigned long)pgd);
 }
 
@@ -255,7 +292,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma,
 
        if (pte_young(*ptep))
                ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,
-                                        &ptep->pte);
+                                        (unsigned long *) &ptep->pte);
 
        if (ret)
                pte_update(vma->vm_mm, addr, ptep);
@@ -274,3 +311,22 @@ int ptep_clear_flush_young(struct vm_area_struct *vma,
 
        return young;
 }
+
+int fixmaps_set;
+
+void __native_set_fixmap(enum fixed_addresses idx, pte_t pte)
+{
+       unsigned long address = __fix_to_virt(idx);
+
+       if (idx >= __end_of_fixed_addresses) {
+               BUG();
+               return;
+       }
+       set_pte_vaddr(address, pte);
+       fixmaps_set++;
+}
+
+void native_set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
+{
+       __native_set_fixmap(idx, pfn_pte(phys >> PAGE_SHIFT, flags));
+}
index 369cf065b6a48f78f9870ddaf9f27e59b6980c0c..b4becbf8c570cfae3d140cbceef0cb74ac7fa2a3 100644 (file)
@@ -71,7 +71,7 @@ void show_mem(void)
  * Associate a virtual page frame with a given physical page frame 
  * and protection flags for that frame.
  */ 
-static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
+void set_pte_vaddr(unsigned long vaddr, pte_t pteval)
 {
        pgd_t *pgd;
        pud_t *pud;
@@ -94,8 +94,8 @@ static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
                return;
        }
        pte = pte_offset_kernel(pmd, vaddr);
-       if (pgprot_val(flags))
-               set_pte_present(&init_mm, vaddr, pte, pfn_pte(pfn, flags));
+       if (pte_val(pteval))
+               set_pte_present(&init_mm, vaddr, pte, pteval);
        else
                pte_clear(&init_mm, vaddr, pte);
 
@@ -141,22 +141,9 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
        __flush_tlb_one(vaddr);
 }
 
-static int fixmaps;
 unsigned long __FIXADDR_TOP = 0xfffff000;
 EXPORT_SYMBOL(__FIXADDR_TOP);
 
-void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
-{
-       unsigned long address = __fix_to_virt(idx);
-
-       if (idx >= __end_of_fixed_addresses) {
-               BUG();
-               return;
-       }
-       set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
-       fixmaps++;
-}
-
 /**
  * reserve_top_address - reserves a hole in the top of kernel address space
  * @reserve - size of hole to reserve
@@ -164,11 +151,44 @@ void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
  * Can be used to relocate the fixmap area and poke a hole in the top
  * of kernel address space to make room for a hypervisor.
  */
-void reserve_top_address(unsigned long reserve)
+void __init reserve_top_address(unsigned long reserve)
 {
-       BUG_ON(fixmaps > 0);
+       BUG_ON(fixmaps_set > 0);
        printk(KERN_INFO "Reserving virtual address space above 0x%08x\n",
               (int)-reserve);
        __FIXADDR_TOP = -reserve - PAGE_SIZE;
        __VMALLOC_RESERVE += reserve;
 }
+
+/*
+ * vmalloc=size forces the vmalloc area to be exactly 'size'
+ * bytes. This can be used to increase (or decrease) the
+ * vmalloc area - the default is 128m.
+ */
+static int __init parse_vmalloc(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+
+       __VMALLOC_RESERVE = memparse(arg, &arg);
+       return 0;
+}
+early_param("vmalloc", parse_vmalloc);
+
+/*
+ * reservetop=size reserves a hole at the top of the kernel address space which
+ * a hypervisor can load into later.  Needed for dynamically loaded hypervisors,
+ * so relocating the fixmap can be done before paging initialization.
+ */
+static int __init parse_reservetop(char *arg)
+{
+       unsigned long address;
+
+       if (!arg)
+               return -EINVAL;
+
+       address = memparse(arg, &arg);
+       reserve_top_address(address);
+       return 0;
+}
+early_param("reservetop", parse_reservetop);
similarity index 56%
rename from arch/x86/kernel/srat_32.c
rename to arch/x86/mm/srat_32.c
index 70e4a374b4e804948998e6711c16ce3682c93e05..f41d67f8f83153b7ed079b05131ad878ac7235be 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/srat.h>
 #include <asm/topology.h>
 #include <asm/smp.h>
+#include <asm/e820.h>
 
 /*
  * proximity macros and definitions
@@ -41,7 +42,7 @@
 #define BMAP_TEST(bmap, bit)   ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit)))
 /* bitmap length; _PXM is at most 255 */
 #define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) 
-static u8 pxm_bitmap[PXM_BITMAP_LEN];  /* bitmap of proximity domains */
+static u8 __initdata pxm_bitmap[PXM_BITMAP_LEN];       /* bitmap of proximity domains */
 
 #define MAX_CHUNKS_PER_NODE    3
 #define MAXCHUNKS              (MAX_CHUNKS_PER_NODE * MAX_NUMNODES)
@@ -52,16 +53,37 @@ struct node_memory_chunk_s {
        u8      nid;            // which cnode contains this chunk?
        u8      bank;           // which mem bank on this node
 };
-static struct node_memory_chunk_s node_memory_chunk[MAXCHUNKS];
+static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS];
 
-static int num_memory_chunks;          /* total number of memory chunks */
+static int __initdata num_memory_chunks; /* total number of memory chunks */
 static u8 __initdata apicid_to_pxm[MAX_APICID];
 
+int numa_off __initdata;
+int acpi_numa __initdata;
+
+static __init void bad_srat(void)
+{
+        printk(KERN_ERR "SRAT: SRAT not used.\n");
+        acpi_numa = -1;
+       num_memory_chunks = 0;
+}
+
+static __init inline int srat_disabled(void)
+{
+       return numa_off || acpi_numa < 0;
+}
+
 /* Identify CPU proximity domains */
-static void __init parse_cpu_affinity_structure(char *p)
+void __init
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *cpu_affinity)
 {
-       struct acpi_srat_cpu_affinity *cpu_affinity =
-                               (struct acpi_srat_cpu_affinity *) p;
+       if (srat_disabled())
+               return;
+       if (cpu_affinity->header.length !=
+            sizeof(struct acpi_srat_cpu_affinity)) {
+               bad_srat();
+               return;
+       }
 
        if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0)
                return;         /* empty entry */
@@ -71,7 +93,7 @@ static void __init parse_cpu_affinity_structure(char *p)
 
        apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo;
 
-       printk("CPU 0x%02X in proximity domain 0x%02X\n",
+       printk(KERN_DEBUG "CPU %02x in proximity domain %02x\n",
                cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo);
 }
 
@@ -79,14 +101,21 @@ static void __init parse_cpu_affinity_structure(char *p)
  * Identify memory proximity domains and hot-remove capabilities.
  * Fill node memory chunk list structure.
  */
-static void __init parse_memory_affinity_structure (char *sratp)
+void __init
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity)
 {
        unsigned long long paddr, size;
        unsigned long start_pfn, end_pfn;
        u8 pxm;
        struct node_memory_chunk_s *p, *q, *pend;
-       struct acpi_srat_mem_affinity *memory_affinity =
-                       (struct acpi_srat_mem_affinity *) sratp;
+
+       if (srat_disabled())
+               return;
+       if (memory_affinity->header.length !=
+            sizeof(struct acpi_srat_mem_affinity)) {
+               bad_srat();
+               return;
+       }
 
        if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0)
                return;         /* empty entry */
@@ -105,7 +134,8 @@ static void __init parse_memory_affinity_structure (char *sratp)
 
 
        if (num_memory_chunks >= MAXCHUNKS) {
-               printk("Too many mem chunks in SRAT. Ignoring %lld MBytes at %llx\n",
+               printk(KERN_WARNING "Too many mem chunks in SRAT."
+                       " Ignoring %lld MBytes at %llx\n",
                        size/(1024*1024), paddr);
                return;
        }
@@ -126,7 +156,8 @@ static void __init parse_memory_affinity_structure (char *sratp)
 
        num_memory_chunks++;
 
-       printk("Memory range 0x%lX to 0x%lX (type 0x%X) in proximity domain 0x%02X %s\n",
+       printk(KERN_DEBUG "Memory range %08lx to %08lx (type %x)"
+                         " in proximity domain %02x %s\n",
                start_pfn, end_pfn,
                memory_affinity->memory_type,
                pxm,
@@ -134,6 +165,14 @@ static void __init parse_memory_affinity_structure (char *sratp)
                 "enabled and removable" : "enabled" ) );
 }
 
+/* Callback for SLIT parsing */
+void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
+{
+}
+
+void acpi_numa_arch_fixup(void)
+{
+}
 /*
  * The SRAT table always lists ascending addresses, so can always
  * assume that the first "start" address that you see is the real
@@ -149,7 +188,7 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c
         * *possible* memory hotplug areas the same as normal RAM.
         */
        if (memory_chunk->start_pfn >= max_pfn) {
-               printk (KERN_INFO "Ignoring SRAT pfns: 0x%08lx -> %08lx\n",
+               printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n",
                        memory_chunk->start_pfn, memory_chunk->end_pfn);
                return;
        }
@@ -166,42 +205,17 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c
                node_end_pfn[nid] = memory_chunk->end_pfn;
 }
 
-/* Parse the ACPI Static Resource Affinity Table */
-static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
+int __init get_memcfg_from_srat(void)
 {
-       u8 *start, *end, *p;
        int i, j, nid;
 
-       start = (u8 *)(&(sratp->reserved) + 1); /* skip header */
-       p = start;
-       end = (u8 *)sratp + sratp->header.length;
 
-       memset(pxm_bitmap, 0, sizeof(pxm_bitmap));      /* init proximity domain bitmap */
-       memset(node_memory_chunk, 0, sizeof(node_memory_chunk));
-
-       num_memory_chunks = 0;
-       while (p < end) {
-               switch (*p) {
-               case ACPI_SRAT_TYPE_CPU_AFFINITY:
-                       parse_cpu_affinity_structure(p);
-                       break;
-               case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
-                       parse_memory_affinity_structure(p);
-                       break;
-               default:
-                       printk("ACPI 2.0 SRAT: unknown entry skipped: type=0x%02X, len=%d\n", p[0], p[1]);
-                       break;
-               }
-               p += p[1];
-               if (p[1] == 0) {
-                       printk("acpi20_parse_srat: Entry length value is zero;"
-                               " can't parse any further!\n");
-                       break;
-               }
-       }
+       if (srat_disabled())
+               goto out_fail;
 
        if (num_memory_chunks == 0) {
-               printk("could not finy any ACPI SRAT memory areas.\n");
+               printk(KERN_WARNING
+                        "could not finy any ACPI SRAT memory areas.\n");
                goto out_fail;
        }
 
@@ -228,131 +242,39 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
        for (i = 0; i < num_memory_chunks; i++)
                node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm);
 
-       printk("pxm bitmap: ");
+       printk(KERN_DEBUG "pxm bitmap: ");
        for (i = 0; i < sizeof(pxm_bitmap); i++) {
-               printk("%02X ", pxm_bitmap[i]);
+               printk(KERN_CONT "%02x ", pxm_bitmap[i]);
        }
-       printk("\n");
-       printk("Number of logical nodes in system = %d\n", num_online_nodes());
-       printk("Number of memory chunks in system = %d\n", num_memory_chunks);
+       printk(KERN_CONT "\n");
+       printk(KERN_DEBUG "Number of logical nodes in system = %d\n",
+                        num_online_nodes());
+       printk(KERN_DEBUG "Number of memory chunks in system = %d\n",
+                        num_memory_chunks);
 
        for (i = 0; i < MAX_APICID; i++)
                apicid_2_node[i] = pxm_to_node(apicid_to_pxm[i]);
 
        for (j = 0; j < num_memory_chunks; j++){
                struct node_memory_chunk_s * chunk = &node_memory_chunk[j];
-               printk("chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
+               printk(KERN_DEBUG
+                       "chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
                       j, chunk->nid, chunk->start_pfn, chunk->end_pfn);
                node_read_chunk(chunk->nid, chunk);
-               add_active_range(chunk->nid, chunk->start_pfn, chunk->end_pfn);
+               e820_register_active_regions(chunk->nid, chunk->start_pfn,
+                                            min(chunk->end_pfn, max_pfn));
        }
+
        for_each_online_node(nid) {
                unsigned long start = node_start_pfn[nid];
-               unsigned long end = node_end_pfn[nid];
+               unsigned long end = min(node_end_pfn[nid], max_pfn);
 
                memory_present(nid, start, end);
                node_remap_size[nid] = node_memmap_size_bytes(nid, start, end);
        }
        return 1;
 out_fail:
-       return 0;
-}
-
-struct acpi_static_rsdt {
-       struct acpi_table_rsdt table;
-       u32 padding[7]; /* Allow for 7 more table entries */
-};
-
-int __init get_memcfg_from_srat(void)
-{
-       struct acpi_table_header *header = NULL;
-       struct acpi_table_rsdp *rsdp = NULL;
-       struct acpi_table_rsdt *rsdt = NULL;
-       acpi_native_uint rsdp_address = 0;
-       struct acpi_static_rsdt saved_rsdt;
-       int tables = 0;
-       int i = 0;
-
-       rsdp_address = acpi_os_get_root_pointer();
-       if (!rsdp_address) {
-               printk("%s: System description tables not found\n",
-                      __func__);
-               goto out_err;
-       }
-
-       printk("%s: assigning address to rsdp\n", __func__);
-       rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address;
-       if (!rsdp) {
-               printk("%s: Didn't find ACPI root!\n", __func__);
-               goto out_err;
-       }
-
-       printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
-               rsdp->oem_id);
-
-       if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) {
-               printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __func__);
-               goto out_err;
-       }
-
-       rsdt = (struct acpi_table_rsdt *)
-           early_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt));
-
-       if (!rsdt) {
-               printk(KERN_WARNING
-                      "%s: ACPI: Invalid root system description tables (RSDT)\n",
-                      __func__);
-               goto out_err;
-       }
-
-       header = &rsdt->header;
-
-       if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) {
-               printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
-               goto out_err;
-       }
-
-       /* 
-        * The number of tables is computed by taking the 
-        * size of all entries (header size minus total 
-        * size of RSDT) divided by the size of each entry
-        * (4-byte table pointers).
-        */
-       tables = (header->length - sizeof(struct acpi_table_header)) / 4;
-
-       if (!tables)
-               goto out_err;
-
-       memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
-
-       if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) {
-               printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n",
-                      saved_rsdt.table.header.length);
-               goto out_err;
-       }
-
-       printk("Begin SRAT table scan....\n");
-
-       for (i = 0; i < tables; i++) {
-               /* Map in header, then map in full table length. */
-               header = (struct acpi_table_header *)
-                       early_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header));
-               if (!header)
-                       break;
-               header = (struct acpi_table_header *)
-                       early_ioremap(saved_rsdt.table.table_offset_entry[i], header->length);
-               if (!header)
-                       break;
-
-               if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4))
-                       continue;
-
-               /* we've found the srat table. don't need to look at any more tables */
-               return acpi20_parse_srat((struct acpi_table_srat *)header);
-       }
-out_err:
-       remove_all_active_ranges();
-       printk("failed to get NUMA memory information from SRAT table\n");
+       printk(KERN_ERR "failed to get NUMA memory information from SRAT"
+                       " table\n");
        return 0;
 }
index 99649dccad28cef2d1399b003dcdd39c04552b5b..1b4763e26ea96f52b6240475e85a04cb3a06dc4b 100644 (file)
@@ -100,7 +100,19 @@ static __init inline int srat_disabled(void)
 /* Callback for SLIT parsing */
 void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
 {
-       acpi_slit = slit;
+       unsigned length;
+       unsigned long phys;
+
+       length = slit->header.length;
+       phys = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, length,
+                PAGE_SIZE);
+
+       if (phys == -1L)
+               panic(" Can not save slit!\n");
+
+       acpi_slit = __va(phys);
+       memcpy(acpi_slit, slit, length);
+       reserve_early(phys, phys + length, "ACPI SLIT");
 }
 
 /* Callback for Proximity Domain -> LAPIC mapping */
@@ -299,7 +311,7 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
                        pxmram = 0;
        }
 
-       e820ram = end_pfn - absent_pages_in_range(0, end_pfn);
+       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) {
                printk(KERN_ERR
@@ -376,7 +388,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))
-                       numa_set_node(i, NUMA_NO_NODE);
+                       numa_clear_node(i);
        }
        numa_init_array();
        return 0;
@@ -495,6 +507,7 @@ int __node_distance(int a, int b)
 
 EXPORT_SYMBOL(__node_distance);
 
+#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
 int memory_add_physaddr_to_nid(u64 start)
 {
        int i, ret = 0;
@@ -506,4 +519,4 @@ int memory_add_physaddr_to_nid(u64 start)
        return ret;
 }
 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-
+#endif
index cc48d3fde545c014dc6d4a34f07cc2578ea0f481..2b6ad5b9f9d53f0012629f5c255f3d12e6d87f82 100644 (file)
@@ -269,12 +269,13 @@ static void nmi_cpu_shutdown(void *dummy)
 
 static void nmi_shutdown(void)
 {
-       struct op_msrs *msrs = &__get_cpu_var(cpu_msrs);
+       struct op_msrs *msrs = &get_cpu_var(cpu_msrs);
        nmi_enabled = 0;
        on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
        unregister_die_notifier(&profile_exceptions_nb);
        model->shutdown(msrs);
        free_msrs();
+       put_cpu_var(cpu_msrs);
 }
 
 static void nmi_cpu_start(void *dummy)
index c5c8e485fc446fffc3fdde5e1d8e6d63306c999f..e515e8db842a0aa4a78ffe617abc7df08b110659 100644 (file)
@@ -1,5 +1,17 @@
-ifeq ($(CONFIG_X86_32),y)
-include ${srctree}/arch/x86/pci/Makefile_32
-else
-include ${srctree}/arch/x86/pci/Makefile_64
-endif
+obj-y                          := i386.o init.o
+
+obj-$(CONFIG_PCI_BIOS)         += pcbios.o
+obj-$(CONFIG_PCI_MMCONFIG)     += mmconfig_$(BITS).o direct.o mmconfig-shared.o
+obj-$(CONFIG_PCI_DIRECT)       += direct.o
+obj-$(CONFIG_PCI_OLPC)         += olpc.o
+
+pci-y                          := fixup.o
+pci-$(CONFIG_ACPI)             += acpi.o
+pci-y                          += legacy.o irq.o
+
+pci-$(CONFIG_X86_VISWS)                += visws.o
+
+pci-$(CONFIG_X86_NUMAQ)                += numa.o
+
+obj-y                          += $(pci-y) common.o early.o
+obj-y                          += amd_bus.o
diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32
deleted file mode 100644 (file)
index 89ec35d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-obj-y                          := i386.o init.o
-
-obj-$(CONFIG_PCI_BIOS)         += pcbios.o
-obj-$(CONFIG_PCI_MMCONFIG)     += mmconfig_32.o direct.o mmconfig-shared.o
-obj-$(CONFIG_PCI_DIRECT)       += direct.o
-obj-$(CONFIG_PCI_OLPC)         += olpc.o
-
-pci-y                          := fixup.o
-
-# Do not change the ordering here. There is a nasty init function
-# ordering dependency which breaks when you move acpi.o below
-# legacy/irq.o
-pci-$(CONFIG_ACPI)             += acpi.o
-pci-y                          += legacy.o irq.o
-
-# Careful: VISWS and NUMAQ overrule the pci-y above. The colons are
-# therefor correct. This needs a proper fix by distangling the code.
-pci-$(CONFIG_X86_VISWS)                := visws.o fixup.o
-pci-$(CONFIG_X86_NUMAQ)                := numa.o irq.o
-
-# Necessary for NUMAQ as well
-pci-$(CONFIG_NUMA)             += mp_bus_to_node.o
-
-obj-y                          += $(pci-y) common.o early.o
diff --git a/arch/x86/pci/Makefile_64 b/arch/x86/pci/Makefile_64
deleted file mode 100644 (file)
index 8fbd198..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for X86_64 specific PCI routines
-#
-# Reuse the i386 PCI subsystem
-#
-EXTRA_CFLAGS += -Iarch/x86/pci
-
-obj-y          := i386.o
-obj-$(CONFIG_PCI_DIRECT)+= direct.o
-obj-y          += fixup.o init.o
-obj-$(CONFIG_ACPI)     += acpi.o
-obj-y                  += legacy.o irq.o common.o early.o
-# mmconfig has a 64bit special
-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o
-
-obj-y          += k8-bus_64.o
-
index d95de2f199cdaf45c3b44663dc32ed884de98b1d..19af06927fbceeb59c7aeb2ca9b7b71248225a4a 100644 (file)
@@ -171,8 +171,11 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
        if (node != -1)
                set_mp_bus_to_node(busnum, node);
        else
-               node = get_mp_bus_to_node(busnum);
 #endif
+               node = get_mp_bus_to_node(busnum);
+
+       if (node != -1 && !node_online(node))
+               node = -1;
 
        /* Allocate per-root-bus (not per bus) arch-specific data.
         * TODO: leak; this memory is never freed.
@@ -204,22 +207,23 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
        if (!bus)
                kfree(sd);
 
+       if (bus && node != -1) {
 #ifdef CONFIG_ACPI_NUMA
-       if (bus) {
-               if (pxm >= 0) {
+               if (pxm >= 0)
                        printk(KERN_DEBUG "bus %02x -> pxm %d -> node %d\n",
-                               busnum, pxm, pxm_to_node(pxm));
-               }
-       }
+                               busnum, pxm, node);
+#else
+               printk(KERN_DEBUG "bus %02x -> node %d\n",
+                       busnum, node);
 #endif
+       }
 
        if (bus && (pci_probe & PCI_USE__CRS))
                get_current_resources(device, busnum, domain, bus);
        return bus;
 }
 
-extern int pci_routeirq;
-static int __init pci_acpi_init(void)
+int __init pci_acpi_init(void)
 {
        struct pci_dev *dev = NULL;
 
@@ -253,4 +257,3 @@ static int __init pci_acpi_init(void)
 
        return 0;
 }
-subsys_initcall(pci_acpi_init);
similarity index 91%
rename from arch/x86/pci/k8-bus_64.c
rename to arch/x86/pci/amd_bus.c
index 5c2799c20e47b7a48b05e1fd15cbdbc79229d86b..a18141ae3f027628b38c15cc126b6600b9e96f75 100644 (file)
@@ -1,40 +1,25 @@
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/topology.h>
+#include "pci.h"
+
+#ifdef CONFIG_X86_64
 #include <asm/pci-direct.h>
 #include <asm/mpspec.h>
 #include <linux/cpumask.h>
-#include <linux/topology.h>
+#endif
 
 /*
  * This discovers the pcibus <-> node mapping on AMD K8.
  * also get peer root bus resource for io,mmio
  */
 
-
-/*
- * sub bus (transparent) will use entres from 3 to store extra from root,
- * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
- */
-#define RES_NUM 16
-struct pci_root_info {
-       char name[12];
-       unsigned int res_num;
-       struct resource res[RES_NUM];
-       int bus_min;
-       int bus_max;
-       int node;
-       int link;
-};
-
-/* 4 at this time, it may become to 32 */
-#define PCI_ROOT_NR 4
-static int pci_root_num;
-static struct pci_root_info pci_root_info[PCI_ROOT_NR];
-
 #ifdef CONFIG_NUMA
 
 #define BUS_NR 256
 
+#ifdef CONFIG_X86_64
+
 static int mp_bus_to_node[BUS_NR];
 
 void set_mp_bus_to_node(int busnum, int node)
@@ -61,7 +46,52 @@ int get_mp_bus_to_node(int busnum)
 
        return node;
 }
-#endif
+
+#else /* CONFIG_X86_32 */
+
+static unsigned char mp_bus_to_node[BUS_NR];
+
+void set_mp_bus_to_node(int busnum, int node)
+{
+       if (busnum >= 0 &&  busnum < BUS_NR)
+       mp_bus_to_node[busnum] = (unsigned char) node;
+}
+
+int get_mp_bus_to_node(int busnum)
+{
+       int node;
+
+       if (busnum < 0 || busnum > (BUS_NR - 1))
+               return 0;
+       node = mp_bus_to_node[busnum];
+       return node;
+}
+
+#endif /* CONFIG_X86_32 */
+
+#endif /* CONFIG_NUMA */
+
+#ifdef CONFIG_X86_64
+
+/*
+ * sub bus (transparent) will use entres from 3 to store extra from root,
+ * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
+ */
+#define RES_NUM 16
+struct pci_root_info {
+       char name[12];
+       unsigned int res_num;
+       struct resource res[RES_NUM];
+       int bus_min;
+       int bus_max;
+       int node;
+       int link;
+};
+
+/* 4 at this time, it may become to 32 */
+#define PCI_ROOT_NR 4
+static int pci_root_num;
+static struct pci_root_info pci_root_info[PCI_ROOT_NR];
 
 void set_pci_bus_resources_arch_default(struct pci_bus *b)
 {
@@ -384,7 +414,7 @@ static int __init early_fill_mp_bus_info(void)
        /* need to take out [0, TOM) for RAM*/
        address = MSR_K8_TOP_MEM1;
        rdmsrl(address, val);
-       end = (val & 0xffffff8000000ULL);
+       end = (val & 0xffffff800000ULL);
        printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20);
        if (end < (1ULL<<32))
                update_range(range, 0, end - 1);
@@ -478,7 +508,7 @@ static int __init early_fill_mp_bus_info(void)
                /* TOP_MEM2 */
                address = MSR_K8_TOP_MEM2;
                rdmsrl(address, val);
-               end = (val & 0xffffff8000000ULL);
+               end = (val & 0xffffff800000ULL);
                printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20);
                update_range(range, 1ULL<<32, end - 1);
        }
@@ -526,3 +556,31 @@ static int __init early_fill_mp_bus_info(void)
 }
 
 postcore_initcall(early_fill_mp_bus_info);
+
+#endif
+
+/* common 32/64 bit code */
+
+#define ENABLE_CF8_EXT_CFG      (1ULL << 46)
+
+static void enable_pci_io_ecs_per_cpu(void *unused)
+{
+       u64 reg;
+       rdmsrl(MSR_AMD64_NB_CFG, reg);
+       if (!(reg & ENABLE_CF8_EXT_CFG)) {
+               reg |= ENABLE_CF8_EXT_CFG;
+               wrmsrl(MSR_AMD64_NB_CFG, reg);
+       }
+}
+
+static int __init enable_pci_io_ecs(void)
+{
+       /* assume all cpus from fam10h have IO ECS */
+        if (boot_cpu_data.x86 < 0x10)
+               return 0;
+       on_each_cpu(enable_pci_io_ecs_per_cpu, NULL, 1, 1);
+       pci_probe |= PCI_HAS_IO_ECS;
+       return 0;
+}
+
+postcore_initcall(enable_pci_io_ecs);
index 6e64aaf00d1dd9473fff8cfd0e6e09074a31443c..20b9f59f95df85203009cce11d688f2510cbeab3 100644 (file)
@@ -384,7 +384,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
 
 extern u8 pci_cache_line_size;
 
-static int __init pcibios_init(void)
+int __init pcibios_init(void)
 {
        struct cpuinfo_x86 *c = &boot_cpu_data;
 
@@ -411,8 +411,6 @@ static int __init pcibios_init(void)
        return 0;
 }
 
-subsys_initcall(pcibios_init);
-
 char * __devinit  pcibios_setup(char *str)
 {
        if (!strcmp(str, "off")) {
index 21d1e0e0d535bfef58228d695b983c747dcea805..9915293500fb69ebdae0b8d80b69155f180f1274 100644 (file)
@@ -8,18 +8,21 @@
 #include "pci.h"
 
 /*
- * Functions for accessing PCI configuration space with type 1 accesses
+ * Functions for accessing PCI base (first 256 bytes) and extended
+ * (4096 bytes per PCI function) configuration space with type 1
+ * accesses.
  */
 
 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
-       (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
+       (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
+       | (devfn << 8) | (reg & 0xFC))
 
 static int pci_conf1_read(unsigned int seg, unsigned int bus,
                          unsigned int devfn, int reg, int len, u32 *value)
 {
        unsigned long flags;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 255)) {
+       if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
                *value = -1;
                return -EINVAL;
        }
@@ -50,7 +53,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus,
 {
        unsigned long flags;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 255)) 
+       if ((bus > 255) || (devfn > 255) || (reg > 4095))
                return -EINVAL;
 
        spin_lock_irqsave(&pci_config_lock, flags);
@@ -260,10 +263,18 @@ void __init pci_direct_init(int type)
                return;
        printk(KERN_INFO "PCI: Using configuration type %d for base access\n",
                 type);
-       if (type == 1)
+       if (type == 1) {
                raw_pci_ops = &pci_direct_conf1;
-       else
-               raw_pci_ops = &pci_direct_conf2;
+               if (raw_pci_ext_ops)
+                       return;
+               if (!(pci_probe & PCI_HAS_IO_ECS))
+                       return;
+               printk(KERN_INFO "PCI: Using configuration type 1 "
+                      "for extended access\n");
+               raw_pci_ext_ops = &pci_direct_conf1;
+               return;
+       }
+       raw_pci_ops = &pci_direct_conf2;
 }
 
 int __init pci_direct_probe(void)
index 10fb308fded8efc85bfbbe7e4630f44342991e0a..2aafb67dc5f1df254de17ff64a1523283c341f32 100644 (file)
@@ -299,9 +299,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                return -EINVAL;
 
        prot = pgprot_val(vma->vm_page_prot);
-       if (pat_wc_enabled && write_combine)
+       if (pat_enabled && write_combine)
                prot |= _PAGE_CACHE_WC;
-       else if (pat_wc_enabled || boot_cpu_data.x86 > 3)
+       else if (pat_enabled || boot_cpu_data.x86 > 3)
                /*
                 * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
                 * To avoid attribute conflicts, request UC MINUS here
@@ -334,7 +334,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                flags = new_flags;
        }
 
-       if (vma->vm_pgoff <= max_pfn_mapped &&
+       if (((vma->vm_pgoff < max_low_pfn_mapped) ||
+            (vma->vm_pgoff >= (1UL<<(32 - PAGE_SHIFT)) &&
+             vma->vm_pgoff < max_pfn_mapped)) &&
            ioremap_change_attr((unsigned long)__va(addr), len, flags)) {
                free_memtype(addr, addr + len);
                return -EINVAL;
index b821f4462d991a6b850886bcd7a9997f14428d46..d6c950f818585aea6df65e38e18c2f85ab217941 100644 (file)
@@ -4,7 +4,7 @@
 
 /* arch_initcall has too random ordering, so call the initializers
    in the right sequence from here. */
-static __init int pci_access_init(void)
+static __init int pci_arch_init(void)
 {
 #ifdef CONFIG_PCI_DIRECT
        int type = 0;
@@ -40,4 +40,4 @@ static __init int pci_access_init(void)
 
        return 0;
 }
-arch_initcall(pci_access_init);
+arch_initcall(pci_arch_init);
index ca8df9c260bc0d9093b37f4a5f3b679a6259dcc9..dc568c6b83f8b5a5203bc0452c06427ae9b97b2a 100644 (file)
@@ -11,8 +11,8 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/dmi.h>
-#include <asm/io.h>
-#include <asm/smp.h>
+#include <linux/io.h>
+#include <linux/smp.h>
 #include <asm/io_apic.h>
 #include <linux/irq.h>
 #include <linux/acpi.h>
@@ -61,7 +61,7 @@ void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL;
  *  and perform checksum verification.
  */
 
-static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
+static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr)
 {
        struct irq_routing_table *rt;
        int i;
@@ -74,7 +74,7 @@ static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
            rt->size < sizeof(struct irq_routing_table))
                return NULL;
        sum = 0;
-       for (i=0; i < rt->size; i++)
+       for (i = 0; i < rt->size; i++)
                sum += addr[i];
        if (!sum) {
                DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt);
@@ -100,7 +100,7 @@ static struct irq_routing_table * __init pirq_find_routing_table(void)
                        return rt;
                printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
        }
-       for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
+       for (addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
                rt = pirq_check_routing_table(addr);
                if (rt)
                        return rt;
@@ -122,20 +122,20 @@ static void __init pirq_peer_trick(void)
        struct irq_info *e;
 
        memset(busmap, 0, sizeof(busmap));
-       for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
+       for (i = 0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
                e = &rt->slots[i];
 #ifdef DEBUG
                {
                        int j;
                        DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
-                       for(j=0; j<4; j++)
+                       for (j = 0; j < 4; j++)
                                DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
                        DBG("\n");
                }
 #endif
                busmap[e->bus] = 1;
        }
-       for(i = 1; i < 256; i++) {
+       for (i = 1; i < 256; i++) {
                int node;
                if (!busmap[i] || pci_find_bus(0, i))
                        continue;
@@ -285,7 +285,7 @@ static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
        static const unsigned char pirqmap[4] = { 1, 0, 2, 3 };
 
        WARN_ON_ONCE(pirq > 4);
-       return read_config_nybble(router,0x43, pirqmap[pirq-1]);
+       return read_config_nybble(router, 0x43, pirqmap[pirq-1]);
 }
 
 static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -314,7 +314,7 @@ static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
 
 /*
  * Cyrix: nibble offset 0x5C
- * 0x5C bits 7:4 is INTB bits 3:0 is INTA 
+ * 0x5C bits 7:4 is INTB bits 3:0 is INTA
  * 0x5D bits 7:4 is INTD bits 3:0 is INTC
  */
 static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
@@ -350,7 +350,7 @@ static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
  *     Apparently there are systems implementing PCI routing table using
  *     link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D.
  *     We try our best to handle both link mappings.
- *     
+ *
  *     Currently (2003-05-21) it appears most SiS chipsets follow the
  *     definition of routing registers from the SiS-5595 southbridge.
  *     According to the SiS 5595 datasheets the revision id's of the
@@ -370,7 +370,7 @@ static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
  *
  *     0x62:   USBIRQ:
  *             bit 6 OHCI function disabled (0), enabled (1)
- *     
+ *
  *     0x6a:   ACPI/SCI IRQ: bits 4-6 reserved
  *
  *     0x7e:   Data Acq. Module IRQ - bits 4-6 reserved
@@ -487,9 +487,7 @@ static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq
        u8 irq;
        irq = 0;
        if (pirq <= 4)
-       {
                irq = read_config_nybble(router, 0x56, pirq - 1);
-       }
        printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
                dev->vendor, dev->device, pirq, irq);
        return irq;
@@ -497,12 +495,10 @@ static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq
 
 static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
 {
-       printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
+       printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n",
                dev->vendor, dev->device, pirq, irq);
        if (pirq <= 4)
-       {
                write_config_nybble(router, 0x56, pirq - 1, irq);
-       }
        return 1;
 }
 
@@ -549,50 +545,49 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
        if (pci_dev_present(pirq_440gx))
                return 0;
 
-       switch(device)
-       {
-               case PCI_DEVICE_ID_INTEL_82371FB_0:
-               case PCI_DEVICE_ID_INTEL_82371SB_0:
-               case PCI_DEVICE_ID_INTEL_82371AB_0:
-               case PCI_DEVICE_ID_INTEL_82371MX:
-               case PCI_DEVICE_ID_INTEL_82443MX_0:
-               case PCI_DEVICE_ID_INTEL_82801AA_0:
-               case PCI_DEVICE_ID_INTEL_82801AB_0:
-               case PCI_DEVICE_ID_INTEL_82801BA_0:
-               case PCI_DEVICE_ID_INTEL_82801BA_10:
-               case PCI_DEVICE_ID_INTEL_82801CA_0:
-               case PCI_DEVICE_ID_INTEL_82801CA_12:
-               case PCI_DEVICE_ID_INTEL_82801DB_0:
-               case PCI_DEVICE_ID_INTEL_82801E_0:
-               case PCI_DEVICE_ID_INTEL_82801EB_0:
-               case PCI_DEVICE_ID_INTEL_ESB_1:
-               case PCI_DEVICE_ID_INTEL_ICH6_0:
-               case PCI_DEVICE_ID_INTEL_ICH6_1:
-               case PCI_DEVICE_ID_INTEL_ICH7_0:
-               case PCI_DEVICE_ID_INTEL_ICH7_1:
-               case PCI_DEVICE_ID_INTEL_ICH7_30:
-               case PCI_DEVICE_ID_INTEL_ICH7_31:
-               case PCI_DEVICE_ID_INTEL_ESB2_0:
-               case PCI_DEVICE_ID_INTEL_ICH8_0:
-               case PCI_DEVICE_ID_INTEL_ICH8_1:
-               case PCI_DEVICE_ID_INTEL_ICH8_2:
-               case PCI_DEVICE_ID_INTEL_ICH8_3:
-               case PCI_DEVICE_ID_INTEL_ICH8_4:
-               case PCI_DEVICE_ID_INTEL_ICH9_0:
-               case PCI_DEVICE_ID_INTEL_ICH9_1:
-               case PCI_DEVICE_ID_INTEL_ICH9_2:
-               case PCI_DEVICE_ID_INTEL_ICH9_3:
-               case PCI_DEVICE_ID_INTEL_ICH9_4:
-               case PCI_DEVICE_ID_INTEL_ICH9_5:
-               case PCI_DEVICE_ID_INTEL_TOLAPAI_0:
-               case PCI_DEVICE_ID_INTEL_ICH10_0:
-               case PCI_DEVICE_ID_INTEL_ICH10_1:
-               case PCI_DEVICE_ID_INTEL_ICH10_2:
-               case PCI_DEVICE_ID_INTEL_ICH10_3:
-                       r->name = "PIIX/ICH";
-                       r->get = pirq_piix_get;
-                       r->set = pirq_piix_set;
-                       return 1;
+       switch (device) {
+       case PCI_DEVICE_ID_INTEL_82371FB_0:
+       case PCI_DEVICE_ID_INTEL_82371SB_0:
+       case PCI_DEVICE_ID_INTEL_82371AB_0:
+       case PCI_DEVICE_ID_INTEL_82371MX:
+       case PCI_DEVICE_ID_INTEL_82443MX_0:
+       case PCI_DEVICE_ID_INTEL_82801AA_0:
+       case PCI_DEVICE_ID_INTEL_82801AB_0:
+       case PCI_DEVICE_ID_INTEL_82801BA_0:
+       case PCI_DEVICE_ID_INTEL_82801BA_10:
+       case PCI_DEVICE_ID_INTEL_82801CA_0:
+       case PCI_DEVICE_ID_INTEL_82801CA_12:
+       case PCI_DEVICE_ID_INTEL_82801DB_0:
+       case PCI_DEVICE_ID_INTEL_82801E_0:
+       case PCI_DEVICE_ID_INTEL_82801EB_0:
+       case PCI_DEVICE_ID_INTEL_ESB_1:
+       case PCI_DEVICE_ID_INTEL_ICH6_0:
+       case PCI_DEVICE_ID_INTEL_ICH6_1:
+       case PCI_DEVICE_ID_INTEL_ICH7_0:
+       case PCI_DEVICE_ID_INTEL_ICH7_1:
+       case PCI_DEVICE_ID_INTEL_ICH7_30:
+       case PCI_DEVICE_ID_INTEL_ICH7_31:
+       case PCI_DEVICE_ID_INTEL_ESB2_0:
+       case PCI_DEVICE_ID_INTEL_ICH8_0:
+       case PCI_DEVICE_ID_INTEL_ICH8_1:
+       case PCI_DEVICE_ID_INTEL_ICH8_2:
+       case PCI_DEVICE_ID_INTEL_ICH8_3:
+       case PCI_DEVICE_ID_INTEL_ICH8_4:
+       case PCI_DEVICE_ID_INTEL_ICH9_0:
+       case PCI_DEVICE_ID_INTEL_ICH9_1:
+       case PCI_DEVICE_ID_INTEL_ICH9_2:
+       case PCI_DEVICE_ID_INTEL_ICH9_3:
+       case PCI_DEVICE_ID_INTEL_ICH9_4:
+       case PCI_DEVICE_ID_INTEL_ICH9_5:
+       case PCI_DEVICE_ID_INTEL_TOLAPAI_0:
+       case PCI_DEVICE_ID_INTEL_ICH10_0:
+       case PCI_DEVICE_ID_INTEL_ICH10_1:
+       case PCI_DEVICE_ID_INTEL_ICH10_2:
+       case PCI_DEVICE_ID_INTEL_ICH10_3:
+               r->name = "PIIX/ICH";
+               r->get = pirq_piix_get;
+               r->set = pirq_piix_set;
+               return 1;
        }
        return 0;
 }
@@ -606,7 +601,7 @@ static __init int via_router_probe(struct irq_router *r,
         * workarounds for some buggy BIOSes
         */
        if (device == PCI_DEVICE_ID_VIA_82C586_0) {
-               switch(router->device) {
+               switch (router->device) {
                case PCI_DEVICE_ID_VIA_82C686:
                        /*
                         * Asus k7m bios wrongly reports 82C686A
@@ -631,7 +626,7 @@ static __init int via_router_probe(struct irq_router *r,
                }
        }
 
-       switch(device) {
+       switch (device) {
        case PCI_DEVICE_ID_VIA_82C586_0:
                r->name = "VIA";
                r->get = pirq_via586_get;
@@ -654,13 +649,12 @@ static __init int via_router_probe(struct irq_router *r,
 
 static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
-               case PCI_DEVICE_ID_VLSI_82C534:
-                       r->name = "VLSI 82C534";
-                       r->get = pirq_vlsi_get;
-                       r->set = pirq_vlsi_set;
-                       return 1;
+       switch (device) {
+       case PCI_DEVICE_ID_VLSI_82C534:
+               r->name = "VLSI 82C534";
+               r->get = pirq_vlsi_get;
+               r->set = pirq_vlsi_set;
+               return 1;
        }
        return 0;
 }
@@ -668,14 +662,13 @@ static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router
 
 static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
-               case PCI_DEVICE_ID_SERVERWORKS_OSB4:
-               case PCI_DEVICE_ID_SERVERWORKS_CSB5:
-                       r->name = "ServerWorks";
-                       r->get = pirq_serverworks_get;
-                       r->set = pirq_serverworks_set;
-                       return 1;
+       switch (device) {
+       case PCI_DEVICE_ID_SERVERWORKS_OSB4:
+       case PCI_DEVICE_ID_SERVERWORKS_CSB5:
+               r->name = "ServerWorks";
+               r->get = pirq_serverworks_get;
+               r->set = pirq_serverworks_set;
+               return 1;
        }
        return 0;
 }
@@ -684,7 +677,7 @@ static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router,
 {
        if (device != PCI_DEVICE_ID_SI_503)
                return 0;
-               
+
        r->name = "SIS";
        r->get = pirq_sis_get;
        r->set = pirq_sis_set;
@@ -693,47 +686,43 @@ static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router,
 
 static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
-               case PCI_DEVICE_ID_CYRIX_5520:
-                       r->name = "NatSemi";
-                       r->get = pirq_cyrix_get;
-                       r->set = pirq_cyrix_set;
-                       return 1;
+       switch (device) {
+       case PCI_DEVICE_ID_CYRIX_5520:
+               r->name = "NatSemi";
+               r->get = pirq_cyrix_get;
+               r->set = pirq_cyrix_set;
+               return 1;
        }
        return 0;
 }
 
 static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
-               case PCI_DEVICE_ID_OPTI_82C700:
-                       r->name = "OPTI";
-                       r->get = pirq_opti_get;
-                       r->set = pirq_opti_set;
-                       return 1;
+       switch (device) {
+       case PCI_DEVICE_ID_OPTI_82C700:
+               r->name = "OPTI";
+               r->get = pirq_opti_get;
+               r->set = pirq_opti_set;
+               return 1;
        }
        return 0;
 }
 
 static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
-               case PCI_DEVICE_ID_ITE_IT8330G_0:
-                       r->name = "ITE";
-                       r->get = pirq_ite_get;
-                       r->set = pirq_ite_set;
-                       return 1;
+       switch (device) {
+       case PCI_DEVICE_ID_ITE_IT8330G_0:
+               r->name = "ITE";
+               r->get = pirq_ite_get;
+               r->set = pirq_ite_set;
+               return 1;
        }
        return 0;
 }
 
 static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
+       switch (device) {
        case PCI_DEVICE_ID_AL_M1533:
        case PCI_DEVICE_ID_AL_M1563:
                printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n");
@@ -747,25 +736,24 @@ static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router,
 
 static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
-       switch(device)
-       {
-               case PCI_DEVICE_ID_AMD_VIPER_740B:
-                       r->name = "AMD756";
-                       break;
-               case PCI_DEVICE_ID_AMD_VIPER_7413:
-                       r->name = "AMD766";
-                       break;
-               case PCI_DEVICE_ID_AMD_VIPER_7443:
-                       r->name = "AMD768";
-                       break;
-               default:
-                       return 0;
+       switch (device) {
+       case PCI_DEVICE_ID_AMD_VIPER_740B:
+               r->name = "AMD756";
+               break;
+       case PCI_DEVICE_ID_AMD_VIPER_7413:
+               r->name = "AMD766";
+               break;
+       case PCI_DEVICE_ID_AMD_VIPER_7443:
+               r->name = "AMD768";
+               break;
+       default:
+               return 0;
        }
        r->get = pirq_amd756_get;
        r->set = pirq_amd756_set;
        return 1;
 }
-               
+
 static __init int pico_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
        switch (device) {
@@ -807,7 +795,7 @@ static struct pci_dev *pirq_router_dev;
  *     FIXME: should we have an option to say "generic for
  *     chipset" ?
  */
+
 static void __init pirq_find_router(struct irq_router *r)
 {
        struct irq_routing_table *rt = pirq_table;
@@ -826,7 +814,7 @@ static void __init pirq_find_router(struct irq_router *r)
        r->name = "default";
        r->get = NULL;
        r->set = NULL;
-       
+
        DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n",
            rt->rtr_vendor, rt->rtr_device);
 
@@ -837,7 +825,7 @@ static void __init pirq_find_router(struct irq_router *r)
                return;
        }
 
-       forh = pirq_routers; h->vendor; h++) {
+       for (h = pirq_routers; h->vendor; h++) {
                /* First look for a router match */
                if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device))
                        break;
@@ -889,7 +877,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
 
        if (!pirq_table)
                return 0;
-       
+
        DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin);
        info = pirq_get_info(dev);
        if (!info) {
@@ -928,8 +916,10 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
         */
        newirq = dev->irq;
        if (newirq && !((1 << newirq) & mask)) {
-               if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
-               else printk("\n" KERN_WARNING
+               if (pci_probe & PCI_USE_PIRQ_MASK)
+                       newirq = 0;
+               else
+                       printk("\n" KERN_WARNING
                        "PCI: IRQ %i for device %s doesn't match PIRQ mask "
                        "- try pci=usepirqmask\n" KERN_DEBUG, newirq,
                        pci_name(dev));
@@ -949,8 +939,8 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
                irq = pirq & 0xf;
                DBG(" -> hardcoded IRQ %d\n", irq);
                msg = "Hardcoded";
-       } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
-       ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
+       } else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
+       ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask))) {
                DBG(" -> got IRQ %d\n", irq);
                msg = "Found";
                eisa_set_level_irq(irq);
@@ -985,15 +975,15 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
                        continue;
                if (info->irq[pin].link == pirq) {
                        /* We refuse to override the dev->irq information. Give a warning! */
-                       if ( dev2->irq && dev2->irq != irq && \
+                       if (dev2->irq && dev2->irq != irq && \
                        (!(pci_probe & PCI_USE_PIRQ_MASK) || \
-                       ((1 << dev2->irq) & mask)) ) {
+                       ((1 << dev2->irq) & mask))) {
 #ifndef CONFIG_PCI_MSI
-                               printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
+                               printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
                                       pci_name(dev2), dev2->irq, irq);
 #endif
-                               continue;
-                       }
+                               continue;
+                       }
                        dev2->irq = irq;
                        pirq_penalty[irq]++;
                        if (dev != dev2)
@@ -1031,8 +1021,7 @@ static void __init pcibios_fixup_irqs(void)
                /*
                 * Recalculate IRQ numbers if we use the I/O APIC.
                 */
-               if (io_apic_assign_pci_irqs)
-               {
+               if (io_apic_assign_pci_irqs) {
                        int irq;
 
                        if (pin) {
@@ -1045,10 +1034,10 @@ static void __init pcibios_fixup_irqs(void)
         * 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;
+                                       struct pci_dev *bridge = dev->bus->self;
 
                                        pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-                                       irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+                                       irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
                                                        PCI_SLOT(bridge->devfn), pin);
                                        if (irq >= 0)
                                                printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n",
@@ -1118,7 +1107,7 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = {
        { }
 };
 
-static int __init pcibios_irq_init(void)
+int __init pcibios_irq_init(void)
 {
        DBG(KERN_DEBUG "PCI: IRQ init\n");
 
@@ -1138,7 +1127,7 @@ static int __init pcibios_irq_init(void)
                pirq_find_router(&pirq_router);
                if (pirq_table->exclusive_irqs) {
                        int i;
-                       for (i=0; i<16; i++)
+                       for (i = 0; i < 16; i++)
                                if (!(pirq_table->exclusive_irqs & (1 << i)))
                                        pirq_penalty[i] += 100;
                }
@@ -1153,9 +1142,6 @@ static int __init pcibios_irq_init(void)
        return 0;
 }
 
-subsys_initcall(pcibios_irq_init);
-
-
 static void pirq_penalize_isa_irq(int irq, int active)
 {
        /*
@@ -1203,10 +1189,10 @@ static int pirq_enable_irq(struct pci_dev *dev)
                         */
                        temp_dev = dev;
                        while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
-                               struct pci_dev * bridge = dev->bus->self;
+                               struct pci_dev *bridge = dev->bus->self;
 
                                pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-                               irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+                               irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
                                                PCI_SLOT(bridge->devfn), pin);
                                if (irq >= 0)
                                        printk(KERN_WARNING "PCI: using PPB %s[%c] to get irq %d\n",
index a67921ce60af1faabf9c8ccbf538b546103ebb04..132876cc6fca3e9d42cd836b2378ee26b4cdf7c7 100644 (file)
@@ -55,4 +55,18 @@ static int __init pci_legacy_init(void)
        return 0;
 }
 
-subsys_initcall(pci_legacy_init);
+int __init pci_subsys_init(void)
+{
+#ifdef CONFIG_ACPI
+       pci_acpi_init();
+#endif
+       pci_legacy_init();
+       pcibios_irq_init();
+#ifdef CONFIG_X86_NUMAQ
+       pci_numa_init();
+#endif
+       pcibios_init();
+
+       return 0;
+}
+subsys_initcall(pci_subsys_init);
index 0cfebecf2a8f128cc2b52f632a95d55eef397fb3..23faaa890ffcd8aac87502d827d3c8d3c7ab7399 100644 (file)
@@ -374,7 +374,7 @@ reject:
 
 static int __initdata known_bridge;
 
-void __init __pci_mmcfg_init(int early)
+static void __init __pci_mmcfg_init(int early)
 {
        /* MMCONFIG disabled */
        if ((pci_probe & PCI_PROBE_MMCONF) == 0)
diff --git a/arch/x86/pci/mp_bus_to_node.c b/arch/x86/pci/mp_bus_to_node.c
deleted file mode 100644 (file)
index 0229439..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/topology.h>
-
-#define BUS_NR 256
-
-static unsigned char mp_bus_to_node[BUS_NR];
-
-void set_mp_bus_to_node(int busnum, int node)
-{
-       if (busnum >= 0 &&  busnum < BUS_NR)
-       mp_bus_to_node[busnum] = (unsigned char) node;
-}
-
-int get_mp_bus_to_node(int busnum)
-{
-       int node;
-
-       if (busnum < 0 || busnum > (BUS_NR - 1))
-               return 0;
-       node = mp_bus_to_node[busnum];
-       return node;
-}
index d9afbae5092b64e6487c4dec7c1e57c35bbc935c..8b5ca1966731a6fd5bd2642696367e99fc12e1f6 100644 (file)
@@ -6,45 +6,21 @@
 #include <linux/init.h>
 #include <linux/nodemask.h>
 #include <mach_apic.h>
+#include <asm/mpspec.h>
 #include "pci.h"
 
 #define XQUAD_PORTIO_BASE 0xfe400000
 #define XQUAD_PORTIO_QUAD 0x40000  /* 256k per quad. */
 
-int mp_bus_id_to_node[MAX_MP_BUSSES];
 #define BUS2QUAD(global) (mp_bus_id_to_node[global])
 
-int mp_bus_id_to_local[MAX_MP_BUSSES];
 #define BUS2LOCAL(global) (mp_bus_id_to_local[global])
 
-void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
-       struct mpc_config_translation *translation)
-{
-       int quad = translation->trans_quad;
-       int local = translation->trans_local;
-
-       mp_bus_id_to_node[m->mpc_busid] = quad;
-       mp_bus_id_to_local[m->mpc_busid] = local;
-       printk(KERN_INFO "Bus #%d is %s (node %d)\n",
-              m->mpc_busid, name, quad);
-}
-
-int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
-void mpc_oem_pci_bus(struct mpc_config_bus *m,
-       struct mpc_config_translation *translation)
-{
-       int quad = translation->trans_quad;
-       int local = translation->trans_local;
-
-       quad_local_to_mp_bus_id[quad][local] = m->mpc_busid;
-}
 
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
 void *xquad_portio;
-#ifdef CONFIG_X86_NUMAQ
 EXPORT_SYMBOL(xquad_portio);
-#endif
 
 #define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
 
@@ -175,10 +151,13 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
 
-static int __init pci_numa_init(void)
+int __init pci_numa_init(void)
 {
        int quad;
 
+       if (!found_numaq)
+               return 0;
+
        raw_pci_ops = &pci_direct_conf1_mq;
 
        if (pcibios_scanned++)
@@ -197,5 +176,3 @@ static int __init pci_numa_init(void)
                }
        return 0;
 }
-
-subsys_initcall(pci_numa_init);
index 720c4c55453462d78770d03506c26ae45d6d2edd..b2270a55b0cf48ed934913d48a6c297cee38e1c8 100644 (file)
@@ -27,6 +27,7 @@
 #define PCI_CAN_SKIP_ISA_ALIGN 0x8000
 #define PCI_USE__CRS           0x10000
 #define PCI_CHECK_ENABLE_AMD_MMCONF    0x20000
+#define PCI_HAS_IO_ECS         0x40000
 
 extern unsigned int pci_probe;
 extern unsigned long pirq_table_addr;
@@ -38,9 +39,6 @@ enum pci_bf_sort_state {
        pci_dmi_bf,
 };
 
-extern void __init dmi_check_pciprobe(void);
-extern void __init dmi_check_skip_isa_align(void);
-
 /* pci-i386.c */
 
 extern unsigned int pcibios_max_latency;
@@ -98,10 +96,19 @@ extern struct pci_raw_ops *raw_pci_ext_ops;
 
 extern struct pci_raw_ops pci_direct_conf1;
 
+/* arch_initcall level */
 extern int pci_direct_probe(void);
 extern void pci_direct_init(int type);
 extern void pci_pcbios_init(void);
 extern int pci_olpc_init(void);
+extern void __init dmi_check_pciprobe(void);
+extern void __init dmi_check_skip_isa_align(void);
+
+/* some common used subsys_initcalls */
+extern int __init pci_acpi_init(void);
+extern int __init pcibios_irq_init(void);
+extern int __init pci_numa_init(void);
+extern int __init pcibios_init(void);
 
 /* pci-mmconfig.c */
 
index c2df4e97eed6ea4d66a971811471e03a3c3ddaa9..1a7bed492bb15647b2f1ce0df3740cd074094781 100644 (file)
@@ -8,18 +8,19 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 
-#include "cobalt.h"
-#include "lithium.h"
+#include <asm/setup.h>
+#include <asm/visws/cobalt.h>
+#include <asm/visws/lithium.h>
 
 #include "pci.h"
 
 static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
 static void pci_visws_disable_irq(struct pci_dev *dev) { }
 
-int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq;
-void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq;
+/* int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; */
+/* void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; */
 
-void __init pcibios_penalize_isa_irq(int irq, int active) {}
+/* void __init pcibios_penalize_isa_irq(int irq, int active) {} */
 
 
 unsigned int pci_bus0, pci_bus1;
@@ -85,7 +86,7 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-static int __init pcibios_init(void)
+static int __init pci_visws_init(void)
 {
        /* The VISWS supports configuration access type 1 only */
        pci_probe = (pci_probe | PCI_PROBE_CONF1) &
@@ -105,4 +106,17 @@ static int __init pcibios_init(void)
        return 0;
 }
 
-subsys_initcall(pcibios_init);
+static __init int pci_subsys_init(void)
+{
+       if (!is_visws_box())
+               return -1;
+
+       pcibios_enable_irq = &pci_visws_enable_irq;
+       pcibios_disable_irq = &pci_visws_disable_irq;
+
+       pci_visws_init();
+       pcibios_init();
+
+       return 0;
+}
+subsys_initcall(pci_subsys_init);
index b542355e0e3433c7c4481fae229b27a1b5d79e18..6dd000dd793394c398a8d02dd9254d6a68fd963b 100644 (file)
@@ -83,7 +83,7 @@ static int set_up_temporary_mappings(void)
 
        /* Set up the direct mapping from scratch */
        start = (unsigned long)pfn_to_kaddr(0);
-       end = (unsigned long)pfn_to_kaddr(end_pfn);
+       end = (unsigned long)pfn_to_kaddr(max_pfn);
 
        for (; start < end; start = next) {
                pud_t *pud = (pud_t *)get_safe_page(GFP_ATOMIC);
index cf058fecfceec989354ec17a3d681cae65315935..0bce5429a51546de1fab7f0acd29e921d38a9870 100644 (file)
@@ -203,20 +203,11 @@ static struct page *vdso32_pages[1];
 
 #ifdef CONFIG_X86_64
 
-static int use_sysenter __read_mostly = -1;
-
-#define        vdso32_sysenter()       (use_sysenter > 0)
+#define        vdso32_sysenter()       (boot_cpu_has(X86_FEATURE_SYSENTER32))
 
 /* May not be __init: called during resume */
 void syscall32_cpu_init(void)
 {
-       if (use_sysenter < 0) {
-               if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
-                       use_sysenter = 1;
-               if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR)
-                       use_sysenter = 1;
-       }
-
        /* Load these always in case some future AMD CPU supports
           SYSENTER from compat mode too. */
        checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
index 3fdd51497a838b801cc69dbd8408ea849da75546..19a6cfaf5db9c2ff89e60ff7c8fa3f4485d9a14b 100644 (file)
@@ -16,7 +16,7 @@
 #include "vextern.h"           /* Just for VMAGIC.  */
 #undef VEXTERN
 
-int vdso_enabled = 1;
+unsigned int __read_mostly vdso_enabled = 1;
 
 extern char vdso_start[], vdso_end[];
 extern unsigned short vdso_sync_cpuid;
index 6c388e593bc804cad3d92f653c1f9ffbb4fd9d3c..c2cc9958087109f9e8e8aa749c0e0b8d693612cd 100644 (file)
@@ -12,3 +12,13 @@ config XEN
          This is the Linux Xen port.  Enabling this will allow the
          kernel to boot in a paravirtualized environment under the
          Xen hypervisor.
+
+config XEN_MAX_DOMAIN_MEMORY
+       int "Maximum allowed size of a domain in gigabytes"
+       default 8
+       depends on XEN
+       help
+         The pseudo-physical to machine address array is sized
+         according to the maximum possible memory size of a Xen
+         domain.  This array uses 1 page per gigabyte, so there's no
+         need to be too stingy here.
\ No newline at end of file
index 3d8df981d5fd8e84cb58993a65d4c2d46a0b3407..2ba2d1649131a1b0151911179679b599a98b9272 100644 (file)
@@ -1,4 +1,4 @@
 obj-y          := enlighten.o setup.o multicalls.o mmu.o \
-                       time.o manage.o xen-asm.o grant-table.o
+                       time.o xen-asm.o grant-table.o suspend.o
 
 obj-$(CONFIG_SMP)      += smp.o
index f09c1c69c37a1498da07524c477e98bfc397ebe6..dcd4e51f2f16829e2e9519615606bc93e4a4cd1e 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/reboot.h>
+#include <asm/pgalloc.h>
 
 #include "xen-ops.h"
 #include "mmu.h"
@@ -75,13 +76,13 @@ DEFINE_PER_CPU(unsigned long, xen_current_cr3);      /* actual vcpu cr3 */
 struct start_info *xen_start_info;
 EXPORT_SYMBOL_GPL(xen_start_info);
 
-static /* __initdata */ struct shared_info dummy_shared_info;
+struct shared_info xen_dummy_shared_info;
 
 /*
  * Point at some empty memory to start with. We map the real shared_info
  * page as soon as fixmap is up and running.
  */
-struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
+struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
 
 /*
  * Flag to determine whether vcpu info placement is available on all
@@ -98,13 +99,13 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
  */
 static int have_vcpu_info_placement = 1;
 
-static void __init xen_vcpu_setup(int cpu)
+static void xen_vcpu_setup(int cpu)
 {
        struct vcpu_register_vcpu_info info;
        int err;
        struct vcpu_info *vcpup;
 
-       BUG_ON(HYPERVISOR_shared_info == &dummy_shared_info);
+       BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
        per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
 
        if (!have_vcpu_info_placement)
@@ -136,11 +137,41 @@ static void __init xen_vcpu_setup(int cpu)
        }
 }
 
+/*
+ * On restore, set the vcpu placement up again.
+ * If it fails, then we're in a bad state, since
+ * we can't back out from using it...
+ */
+void xen_vcpu_restore(void)
+{
+       if (have_vcpu_info_placement) {
+               int cpu;
+
+               for_each_online_cpu(cpu) {
+                       bool other_cpu = (cpu != smp_processor_id());
+
+                       if (other_cpu &&
+                           HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
+                               BUG();
+
+                       xen_vcpu_setup(cpu);
+
+                       if (other_cpu &&
+                           HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
+                               BUG();
+               }
+
+               BUG_ON(!have_vcpu_info_placement);
+       }
+}
+
 static void __init xen_banner(void)
 {
        printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
               pv_info.name);
-       printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic);
+       printk(KERN_INFO "Hypervisor signature: %s%s\n",
+              xen_start_info->magic,
+              xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
 }
 
 static void xen_cpuid(unsigned int *ax, unsigned int *bx,
@@ -235,13 +266,13 @@ static void xen_irq_enable(void)
 {
        struct vcpu_info *vcpu;
 
-       /* There's a one instruction preempt window here.  We need to
-          make sure we're don't switch CPUs between getting the vcpu
-          pointer and updating the mask. */
-       preempt_disable();
+       /* We don't need to worry about being preempted here, since
+          either a) interrupts are disabled, so no preemption, or b)
+          the caller is confused and is trying to re-enable interrupts
+          on an indeterminate processor. */
+
        vcpu = x86_read_percpu(xen_vcpu);
        vcpu->evtchn_upcall_mask = 0;
-       preempt_enable_no_resched();
 
        /* Doesn't matter if we get preempted here, because any
           pending event will get dealt with anyway. */
@@ -254,7 +285,7 @@ static void xen_irq_enable(void)
 static void xen_safe_halt(void)
 {
        /* Blocking includes an implicit local_irq_enable(). */
-       if (HYPERVISOR_sched_op(SCHEDOP_block, 0) != 0)
+       if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
                BUG();
 }
 
@@ -607,6 +638,30 @@ static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
+static void xen_clts(void)
+{
+       struct multicall_space mcs;
+
+       mcs = xen_mc_entry(0);
+
+       MULTI_fpu_taskswitch(mcs.mc, 0);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_write_cr0(unsigned long cr0)
+{
+       struct multicall_space mcs;
+
+       /* Only pay attention to cr0.TS; everything else is
+          ignored. */
+       mcs = xen_mc_entry(0);
+
+       MULTI_fpu_taskswitch(mcs.mc, (cr0 & X86_CR0_TS) != 0);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
 static void xen_write_cr2(unsigned long cr2)
 {
        x86_read_percpu(xen_vcpu)->arch.cr2 = cr2;
@@ -624,8 +679,10 @@ static unsigned long xen_read_cr2_direct(void)
 
 static void xen_write_cr4(unsigned long cr4)
 {
-       /* Just ignore cr4 changes; Xen doesn't allow us to do
-          anything anyway. */
+       cr4 &= ~X86_CR4_PGE;
+       cr4 &= ~X86_CR4_PSE;
+
+       native_write_cr4(cr4);
 }
 
 static unsigned long xen_read_cr3(void)
@@ -831,7 +888,7 @@ static __init void xen_pagetable_setup_start(pgd_t *base)
                          PFN_DOWN(__pa(xen_start_info->pt_base)));
 }
 
-static __init void setup_shared_info(void)
+void xen_setup_shared_info(void)
 {
        if (!xen_feature(XENFEAT_auto_translated_physmap)) {
                unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP);
@@ -854,6 +911,8 @@ static __init void setup_shared_info(void)
        /* In UP this is as good a place as any to set up shared info */
        xen_setup_vcpu_info_placement();
 #endif
+
+       xen_setup_mfn_list_list();
 }
 
 static __init void xen_pagetable_setup_done(pgd_t *base)
@@ -866,15 +925,23 @@ static __init void xen_pagetable_setup_done(pgd_t *base)
        pv_mmu_ops.release_pmd = xen_release_pmd;
        pv_mmu_ops.set_pte = xen_set_pte;
 
-       setup_shared_info();
+       xen_setup_shared_info();
 
        /* Actually pin the pagetable down, but we can't set PG_pinned
           yet because the page structures don't exist yet. */
        pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(base)));
 }
 
+static __init void xen_post_allocator_init(void)
+{
+       pv_mmu_ops.set_pmd = xen_set_pmd;
+       pv_mmu_ops.set_pud = xen_set_pud;
+
+       xen_mark_init_mm_pinned();
+}
+
 /* This is called once we have the cpu_possible_map */
-void __init xen_setup_vcpu_info_placement(void)
+void xen_setup_vcpu_info_placement(void)
 {
        int cpu;
 
@@ -947,6 +1014,33 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
        return ret;
 }
 
+static void xen_set_fixmap(unsigned idx, unsigned long phys, pgprot_t prot)
+{
+       pte_t pte;
+
+       phys >>= PAGE_SHIFT;
+
+       switch (idx) {
+       case FIX_BTMAP_END ... FIX_BTMAP_BEGIN:
+#ifdef CONFIG_X86_F00F_BUG
+       case FIX_F00F_IDT:
+#endif
+       case FIX_WP_TEST:
+       case FIX_VDSO:
+#ifdef CONFIG_X86_LOCAL_APIC
+       case FIX_APIC_BASE:     /* maps dummy local APIC */
+#endif
+               pte = pfn_pte(phys, prot);
+               break;
+
+       default:
+               pte = mfn_pte(phys, prot);
+               break;
+       }
+
+       __native_set_fixmap(idx, pte);
+}
+
 static const struct pv_info xen_info __initdata = {
        .paravirt_enabled = 1,
        .shared_kernel_pmd = 0,
@@ -960,7 +1054,7 @@ static const struct pv_init_ops xen_init_ops __initdata = {
        .banner = xen_banner,
        .memory_setup = xen_memory_setup,
        .arch_setup = xen_arch_setup,
-       .post_allocator_init = xen_mark_init_mm_pinned,
+       .post_allocator_init = xen_post_allocator_init,
 };
 
 static const struct pv_time_ops xen_time_ops __initdata = {
@@ -968,7 +1062,7 @@ static const struct pv_time_ops xen_time_ops __initdata = {
 
        .set_wallclock = xen_set_wallclock,
        .get_wallclock = xen_get_wallclock,
-       .get_cpu_khz = xen_cpu_khz,
+       .get_tsc_khz = xen_tsc_khz,
        .sched_clock = xen_sched_clock,
 };
 
@@ -978,10 +1072,10 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        .set_debugreg = xen_set_debugreg,
        .get_debugreg = xen_get_debugreg,
 
-       .clts = native_clts,
+       .clts = xen_clts,
 
        .read_cr0 = native_read_cr0,
-       .write_cr0 = native_write_cr0,
+       .write_cr0 = xen_write_cr0,
 
        .read_cr4 = native_read_cr4,
        .read_cr4_safe = native_read_cr4_safe,
@@ -995,7 +1089,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        .read_pmc = native_read_pmc,
 
        .iret = xen_iret,
-       .irq_enable_syscall_ret = xen_sysexit,
+       .irq_enable_sysexit = xen_sysexit,
 
        .load_tr_desc = paravirt_nop,
        .set_ldt = xen_set_ldt,
@@ -1029,6 +1123,9 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
        .irq_enable = xen_irq_enable,
        .safe_halt = xen_safe_halt,
        .halt = xen_halt,
+#ifdef CONFIG_X86_64
+       .adjust_exception_frame = paravirt_nop,
+#endif
 };
 
 static const struct pv_apic_ops xen_apic_ops __initdata = {
@@ -1060,6 +1157,9 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
        .pte_update = paravirt_nop,
        .pte_update_defer = paravirt_nop,
 
+       .pgd_alloc = __paravirt_pgd_alloc,
+       .pgd_free = paravirt_nop,
+
        .alloc_pte = xen_alloc_pte_init,
        .release_pte = xen_release_pte_init,
        .alloc_pmd = xen_alloc_pte_init,
@@ -1072,9 +1172,13 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
        .set_pte = NULL,        /* see xen_pagetable_setup_* */
        .set_pte_at = xen_set_pte_at,
-       .set_pmd = xen_set_pmd,
+       .set_pmd = xen_set_pmd_hyper,
+
+       .ptep_modify_prot_start = __ptep_modify_prot_start,
+       .ptep_modify_prot_commit = __ptep_modify_prot_commit,
 
        .pte_val = xen_pte_val,
+       .pte_flags = native_pte_val,
        .pgd_val = xen_pgd_val,
 
        .make_pte = xen_make_pte,
@@ -1082,7 +1186,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
 
        .set_pte_atomic = xen_set_pte_atomic,
        .set_pte_present = xen_set_pte_at,
-       .set_pud = xen_set_pud,
+       .set_pud = xen_set_pud_hyper,
        .pte_clear = xen_pte_clear,
        .pmd_clear = xen_pmd_clear,
 
@@ -1097,6 +1201,8 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
                .enter = paravirt_enter_lazy_mmu,
                .leave = xen_leave_lazy,
        },
+
+       .set_fixmap = xen_set_fixmap,
 };
 
 #ifdef CONFIG_SMP
@@ -1114,11 +1220,13 @@ static const struct smp_ops xen_smp_ops __initdata = {
 
 static void xen_reboot(int reason)
 {
+       struct sched_shutdown r = { .reason = reason };
+
 #ifdef CONFIG_SMP
        smp_send_stop();
 #endif
 
-       if (HYPERVISOR_sched_op(SCHEDOP_shutdown, reason))
+       if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r))
                BUG();
 }
 
@@ -1173,6 +1281,8 @@ asmlinkage void __init xen_start_kernel(void)
 
        BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
 
+       xen_setup_features();
+
        /* Install Xen paravirt ops */
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
@@ -1182,21 +1292,26 @@ asmlinkage void __init xen_start_kernel(void)
        pv_apic_ops = xen_apic_ops;
        pv_mmu_ops = xen_mmu_ops;
 
+       if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
+               pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start;
+               pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit;
+       }
+
        machine_ops = xen_machine_ops;
 
 #ifdef CONFIG_SMP
        smp_ops = xen_smp_ops;
 #endif
 
-       xen_setup_features();
-
        /* Get mfn list */
        if (!xen_feature(XENFEAT_auto_translated_physmap))
-               phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list;
+               xen_build_dynamic_phys_to_machine();
 
        pgd = (pgd_t *)xen_start_info->pt_base;
 
+       init_pg_tables_start = __pa(pgd);
        init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE;
+       max_pfn_mapped = (init_pg_tables_end + 512*1024) >> PAGE_SHIFT;
 
        init_mm.pgd = pgd; /* use the Xen pagetables to start */
 
@@ -1232,9 +1347,12 @@ asmlinkage void __init xen_start_kernel(void)
                ? __pa(xen_start_info->mod_start) : 0;
        boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
 
-       if (!is_initial_xendomain())
+       if (!is_initial_xendomain()) {
+               add_preferred_console("xenboot", 0, NULL);
+               add_preferred_console("tty", 0, NULL);
                add_preferred_console("hvc", 0, NULL);
+       }
 
        /* Start the world */
-       start_kernel();
+       i386_start_kernel();
 }
diff --git a/arch/x86/xen/manage.c b/arch/x86/xen/manage.c
deleted file mode 100644 (file)
index aa7af9e..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Handle extern requests for shutdown, reboot and sysrq
- */
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/reboot.h>
-#include <linux/sysrq.h>
-
-#include <xen/xenbus.h>
-
-#define SHUTDOWN_INVALID  -1
-#define SHUTDOWN_POWEROFF  0
-#define SHUTDOWN_SUSPEND   2
-/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
- * report a crash, not be instructed to crash!
- * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
- * the distinction when we return the reason code to them.
- */
-#define SHUTDOWN_HALT      4
-
-/* Ignore multiple shutdown requests. */
-static int shutting_down = SHUTDOWN_INVALID;
-
-static void shutdown_handler(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len)
-{
-       char *str;
-       struct xenbus_transaction xbt;
-       int err;
-
-       if (shutting_down != SHUTDOWN_INVALID)
-               return;
-
- again:
-       err = xenbus_transaction_start(&xbt);
-       if (err)
-               return;
-
-       str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
-       /* Ignore read errors and empty reads. */
-       if (XENBUS_IS_ERR_READ(str)) {
-               xenbus_transaction_end(xbt, 1);
-               return;
-       }
-
-       xenbus_write(xbt, "control", "shutdown", "");
-
-       err = xenbus_transaction_end(xbt, 0);
-       if (err == -EAGAIN) {
-               kfree(str);
-               goto again;
-       }
-
-       if (strcmp(str, "poweroff") == 0 ||
-           strcmp(str, "halt") == 0)
-               orderly_poweroff(false);
-       else if (strcmp(str, "reboot") == 0)
-               ctrl_alt_del();
-       else {
-               printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
-               shutting_down = SHUTDOWN_INVALID;
-       }
-
-       kfree(str);
-}
-
-static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
-                         unsigned int len)
-{
-       char sysrq_key = '\0';
-       struct xenbus_transaction xbt;
-       int err;
-
- again:
-       err = xenbus_transaction_start(&xbt);
-       if (err)
-               return;
-       if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
-               printk(KERN_ERR "Unable to read sysrq code in "
-                      "control/sysrq\n");
-               xenbus_transaction_end(xbt, 1);
-               return;
-       }
-
-       if (sysrq_key != '\0')
-               xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
-
-       err = xenbus_transaction_end(xbt, 0);
-       if (err == -EAGAIN)
-               goto again;
-
-       if (sysrq_key != '\0')
-               handle_sysrq(sysrq_key, NULL);
-}
-
-static struct xenbus_watch shutdown_watch = {
-       .node = "control/shutdown",
-       .callback = shutdown_handler
-};
-
-static struct xenbus_watch sysrq_watch = {
-       .node = "control/sysrq",
-       .callback = sysrq_handler
-};
-
-static int setup_shutdown_watcher(void)
-{
-       int err;
-
-       err = register_xenbus_watch(&shutdown_watch);
-       if (err) {
-               printk(KERN_ERR "Failed to set shutdown watcher\n");
-               return err;
-       }
-
-       err = register_xenbus_watch(&sysrq_watch);
-       if (err) {
-               printk(KERN_ERR "Failed to set sysrq watcher\n");
-               return err;
-       }
-
-       return 0;
-}
-
-static int shutdown_event(struct notifier_block *notifier,
-                         unsigned long event,
-                         void *data)
-{
-       setup_shutdown_watcher();
-       return NOTIFY_DONE;
-}
-
-static int __init setup_shutdown_event(void)
-{
-       static struct notifier_block xenstore_notifier = {
-               .notifier_call = shutdown_event
-       };
-       register_xenstore_notifier(&xenstore_notifier);
-
-       return 0;
-}
-
-subsys_initcall(setup_shutdown_event);
index 4e527e7893a8c134481aac1c3e7ed621882745ad..42b3b9ed641d6b4cf81f38a1ca86bccc76c415da 100644 (file)
 #include "multicalls.h"
 #include "mmu.h"
 
+#define P2M_ENTRIES_PER_PAGE   (PAGE_SIZE / sizeof(unsigned long))
+#define TOP_ENTRIES            (MAX_DOMAIN_PAGES / P2M_ENTRIES_PER_PAGE)
+
+/* Placeholder for holes in the address space */
+static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE]
+       __attribute__((section(".data.page_aligned"))) =
+               { [ 0 ... P2M_ENTRIES_PER_PAGE-1 ] = ~0UL };
+
+ /* Array of pointers to pages containing p2m entries */
+static unsigned long *p2m_top[TOP_ENTRIES]
+       __attribute__((section(".data.page_aligned"))) =
+               { [ 0 ... TOP_ENTRIES - 1] = &p2m_missing[0] };
+
+/* Arrays of p2m arrays expressed in mfns used for save/restore */
+static unsigned long p2m_top_mfn[TOP_ENTRIES]
+       __attribute__((section(".bss.page_aligned")));
+
+static unsigned long p2m_top_mfn_list[
+                       PAGE_ALIGN(TOP_ENTRIES / P2M_ENTRIES_PER_PAGE)]
+       __attribute__((section(".bss.page_aligned")));
+
+static inline unsigned p2m_top_index(unsigned long pfn)
+{
+       BUG_ON(pfn >= MAX_DOMAIN_PAGES);
+       return pfn / P2M_ENTRIES_PER_PAGE;
+}
+
+static inline unsigned p2m_index(unsigned long pfn)
+{
+       return pfn % P2M_ENTRIES_PER_PAGE;
+}
+
+/* Build the parallel p2m_top_mfn structures */
+void xen_setup_mfn_list_list(void)
+{
+       unsigned pfn, idx;
+
+       for(pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
+               unsigned topidx = p2m_top_index(pfn);
+
+               p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]);
+       }
+
+       for(idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
+               unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
+               p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
+       }
+
+       BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
+
+       HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
+               virt_to_mfn(p2m_top_mfn_list);
+       HYPERVISOR_shared_info->arch.max_pfn = xen_start_info->nr_pages;
+}
+
+/* Set up p2m_top to point to the domain-builder provided p2m pages */
+void __init xen_build_dynamic_phys_to_machine(void)
+{
+       unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
+       unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
+       unsigned pfn;
+
+       for(pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
+               unsigned topidx = p2m_top_index(pfn);
+
+               p2m_top[topidx] = &mfn_list[pfn];
+       }
+}
+
+unsigned long get_phys_to_machine(unsigned long pfn)
+{
+       unsigned topidx, idx;
+
+       if (unlikely(pfn >= MAX_DOMAIN_PAGES))
+               return INVALID_P2M_ENTRY;
+
+       topidx = p2m_top_index(pfn);
+       idx = p2m_index(pfn);
+       return p2m_top[topidx][idx];
+}
+EXPORT_SYMBOL_GPL(get_phys_to_machine);
+
+static void alloc_p2m(unsigned long **pp, unsigned long *mfnp)
+{
+       unsigned long *p;
+       unsigned i;
+
+       p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
+       BUG_ON(p == NULL);
+
+       for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
+               p[i] = INVALID_P2M_ENTRY;
+
+       if (cmpxchg(pp, p2m_missing, p) != p2m_missing)
+               free_page((unsigned long)p);
+       else
+               *mfnp = virt_to_mfn(p);
+}
+
+void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+{
+       unsigned topidx, idx;
+
+       if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
+               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+               return;
+       }
+
+       if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
+               BUG_ON(mfn != INVALID_P2M_ENTRY);
+               return;
+       }
+
+       topidx = p2m_top_index(pfn);
+       if (p2m_top[topidx] == p2m_missing) {
+               /* no need to allocate a page to store an invalid entry */
+               if (mfn == INVALID_P2M_ENTRY)
+                       return;
+               alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]);
+       }
+
+       idx = p2m_index(pfn);
+       p2m_top[topidx][idx] = mfn;
+}
+
 xmaddr_t arbitrary_virt_to_machine(unsigned long address)
 {
        unsigned int level;
@@ -98,24 +223,60 @@ void make_lowmem_page_readwrite(void *vaddr)
 }
 
 
-void xen_set_pmd(pmd_t *ptr, pmd_t val)
+static bool page_pinned(void *ptr)
+{
+       struct page *page = virt_to_page(ptr);
+
+       return PagePinned(page);
+}
+
+static void extend_mmu_update(const struct mmu_update *update)
 {
        struct multicall_space mcs;
        struct mmu_update *u;
 
-       preempt_disable();
+       mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
+
+       if (mcs.mc != NULL)
+               mcs.mc->args[1]++;
+       else {
+               mcs = __xen_mc_entry(sizeof(*u));
+               MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+       }
 
-       mcs = xen_mc_entry(sizeof(*u));
        u = mcs.args;
-       u->ptr = virt_to_machine(ptr).maddr;
-       u->val = pmd_val_ma(val);
-       MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+       *u = *update;
+}
+
+void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
+{
+       struct mmu_update u;
+
+       preempt_disable();
+
+       xen_mc_batch();
+
+       u.ptr = virt_to_machine(ptr).maddr;
+       u.val = pmd_val_ma(val);
+       extend_mmu_update(&u);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
        preempt_enable();
 }
 
+void xen_set_pmd(pmd_t *ptr, pmd_t val)
+{
+       /* If page is not pinned, we can just update the entry
+          directly */
+       if (!page_pinned(ptr)) {
+               *ptr = val;
+               return;
+       }
+
+       xen_set_pmd_hyper(ptr, val);
+}
+
 /*
  * Associate a virtual page frame with a given physical page frame
  * and protection flags for that frame.
@@ -179,6 +340,26 @@ out:
                preempt_enable();
 }
 
+pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+       /* Just return the pte as-is.  We preserve the bits on commit */
+       return *ptep;
+}
+
+void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
+                                pte_t *ptep, pte_t pte)
+{
+       struct mmu_update u;
+
+       xen_mc_batch();
+
+       u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
+       u.val = pte_val_ma(pte);
+       extend_mmu_update(&u);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
 /* Assume pteval_t is equivalent to all the other *val_t types. */
 static pteval_t pte_mfn_to_pfn(pteval_t val)
 {
@@ -229,24 +410,35 @@ pmdval_t xen_pmd_val(pmd_t pmd)
        return pte_mfn_to_pfn(pmd.pmd);
 }
 
-void xen_set_pud(pud_t *ptr, pud_t val)
+void xen_set_pud_hyper(pud_t *ptr, pud_t val)
 {
-       struct multicall_space mcs;
-       struct mmu_update *u;
+       struct mmu_update u;
 
        preempt_disable();
 
-       mcs = xen_mc_entry(sizeof(*u));
-       u = mcs.args;
-       u->ptr = virt_to_machine(ptr).maddr;
-       u->val = pud_val_ma(val);
-       MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+       xen_mc_batch();
+
+       u.ptr = virt_to_machine(ptr).maddr;
+       u.val = pud_val_ma(val);
+       extend_mmu_update(&u);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
        preempt_enable();
 }
 
+void xen_set_pud(pud_t *ptr, pud_t val)
+{
+       /* If page is not pinned, we can just update the entry
+          directly */
+       if (!page_pinned(ptr)) {
+               *ptr = val;
+               return;
+       }
+
+       xen_set_pud_hyper(ptr, val);
+}
+
 void xen_set_pte(pte_t *ptep, pte_t pte)
 {
        ptep->pte_high = pte.pte_high;
@@ -268,7 +460,7 @@ void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 
 void xen_pmd_clear(pmd_t *pmdp)
 {
-       xen_set_pmd(pmdp, __pmd(0));
+       set_pmd(pmdp, __pmd(0));
 }
 
 pmd_t xen_make_pmd(pmdval_t pmd)
@@ -441,6 +633,29 @@ void xen_pgd_pin(pgd_t *pgd)
        xen_mc_issue(0);
 }
 
+/*
+ * On save, we need to pin all pagetables to make sure they get their
+ * mfns turned into pfns.  Search the list for any unpinned pgds and pin
+ * them (unpinned pgds are not currently in use, probably because the
+ * process is under construction or destruction).
+ */
+void xen_mm_pin_all(void)
+{
+       unsigned long flags;
+       struct page *page;
+
+       spin_lock_irqsave(&pgd_lock, flags);
+
+       list_for_each_entry(page, &pgd_list, lru) {
+               if (!PagePinned(page)) {
+                       xen_pgd_pin((pgd_t *)page_address(page));
+                       SetPageSavePinned(page);
+               }
+       }
+
+       spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
 /* The init_mm pagetable is really pinned as soon as its created, but
    that's before we have page structures to store the bits.  So do all
    the book-keeping now. */
@@ -498,6 +713,29 @@ static void xen_pgd_unpin(pgd_t *pgd)
        xen_mc_issue(0);
 }
 
+/*
+ * On resume, undo any pinning done at save, so that the rest of the
+ * kernel doesn't see any unexpected pinned pagetables.
+ */
+void xen_mm_unpin_all(void)
+{
+       unsigned long flags;
+       struct page *page;
+
+       spin_lock_irqsave(&pgd_lock, flags);
+
+       list_for_each_entry(page, &pgd_list, lru) {
+               if (PageSavePinned(page)) {
+                       BUG_ON(!PagePinned(page));
+                       printk("unpinning pinned %p\n", page_address(page));
+                       xen_pgd_unpin((pgd_t *)page_address(page));
+                       ClearPageSavePinned(page);
+               }
+       }
+
+       spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
 void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        spin_lock(&next->page_table_lock);
@@ -591,7 +829,7 @@ void xen_exit_mmap(struct mm_struct *mm)
        spin_lock(&mm->page_table_lock);
 
        /* pgd may not be pinned in the error exit path of execve */
-       if (PagePinned(virt_to_page(mm->pgd)))
+       if (page_pinned(mm->pgd))
                xen_pgd_unpin(mm->pgd);
 
        spin_unlock(&mm->page_table_lock);
index 5fe961caffd4bf3b28720a304bcb055fec558c68..297bf9f5b8bc3c5a709ff811078c874ffe9b2bab 100644 (file)
@@ -25,10 +25,6 @@ enum pt_level {
 
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
-void xen_set_pte(pte_t *ptep, pte_t pteval);
-void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
-                   pte_t *ptep, pte_t pteval);
-void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
 
 void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
@@ -45,11 +41,19 @@ pte_t xen_make_pte(pteval_t);
 pmd_t xen_make_pmd(pmdval_t);
 pgd_t xen_make_pgd(pgdval_t);
 
+void xen_set_pte(pte_t *ptep, pte_t pteval);
 void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
                    pte_t *ptep, pte_t pteval);
 void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
+void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
 void xen_set_pud(pud_t *ptr, pud_t val);
+void xen_set_pmd_hyper(pmd_t *pmdp, pmd_t pmdval);
+void xen_set_pud_hyper(pud_t *ptr, pud_t val);
 void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
 void xen_pmd_clear(pmd_t *pmdp);
 
+pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+void  xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
+                                 pte_t *ptep, pte_t pte);
+
 #endif /* _XEN_MMU_H */
index 5791eb2e37508dc87ab6d9f74bdc53da6f24ae4b..3c63c4da7ed19cbe4ae43234fe6f6068eb638a79 100644 (file)
 #define MC_DEBUG       1
 
 #define MC_BATCH       32
-#define MC_ARGS                (MC_BATCH * 16 / sizeof(u64))
+#define MC_ARGS                (MC_BATCH * 16)
 
 struct mc_buffer {
        struct multicall_entry entries[MC_BATCH];
 #if MC_DEBUG
        struct multicall_entry debug[MC_BATCH];
 #endif
-       u64 args[MC_ARGS];
+       unsigned char args[MC_ARGS];
        struct callback {
                void (*fn)(void *);
                void *data;
@@ -107,20 +107,48 @@ struct multicall_space __xen_mc_entry(size_t args)
 {
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
        struct multicall_space ret;
-       unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64);
+       unsigned argidx = roundup(b->argidx, sizeof(u64));
 
        BUG_ON(preemptible());
-       BUG_ON(argspace > MC_ARGS);
+       BUG_ON(b->argidx > MC_ARGS);
 
        if (b->mcidx == MC_BATCH ||
-           (b->argidx + argspace) > MC_ARGS)
+           (argidx + args) > MC_ARGS) {
                xen_mc_flush();
+               argidx = roundup(b->argidx, sizeof(u64));
+       }
 
        ret.mc = &b->entries[b->mcidx];
        b->mcidx++;
+       ret.args = &b->args[argidx];
+       b->argidx = argidx + args;
+
+       BUG_ON(b->argidx > MC_ARGS);
+       return ret;
+}
+
+struct multicall_space xen_mc_extend_args(unsigned long op, size_t size)
+{
+       struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+       struct multicall_space ret = { NULL, NULL };
+
+       BUG_ON(preemptible());
+       BUG_ON(b->argidx > MC_ARGS);
+
+       if (b->mcidx == 0)
+               return ret;
+
+       if (b->entries[b->mcidx - 1].op != op)
+               return ret;
+
+       if ((b->argidx + size) > MC_ARGS)
+               return ret;
+
+       ret.mc = &b->entries[b->mcidx - 1];
        ret.args = &b->args[b->argidx];
-       b->argidx += argspace;
+       b->argidx += size;
 
+       BUG_ON(b->argidx > MC_ARGS);
        return ret;
 }
 
index 8bae996d99a39c2c190de046f6be91b47060aacf..858938241616ab88ff53700a4463c698c11dad3d 100644 (file)
@@ -45,4 +45,16 @@ static inline void xen_mc_issue(unsigned mode)
 /* Set up a callback to be called when the current batch is flushed */
 void xen_mc_callback(void (*fn)(void *), void *data);
 
+/*
+ * Try to extend the arguments of the previous multicall command.  The
+ * previous command's op must match.  If it does, then it attempts to
+ * extend the argument space allocated to the multicall entry by
+ * arg_size bytes.
+ *
+ * The returned multicall_space will return with mc pointing to the
+ * command on success, or NULL on failure, and args pointing to the
+ * newly allocated space.
+ */
+struct multicall_space xen_mc_extend_args(unsigned long op, size_t arg_size);
+
 #endif /* _XEN_MULTICALLS_H */
index 82517e4a752a19049c0177768851f48a1190a639..e0a39595bde3b342c8364a4306f3b8ea61d88def 100644 (file)
 #include <asm/vdso.h>
 #include <asm/e820.h>
 #include <asm/setup.h>
+#include <asm/acpi.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
+#include <xen/page.h>
 #include <xen/interface/callback.h>
 #include <xen/interface/physdev.h>
 #include <xen/features.h>
@@ -27,8 +29,6 @@
 extern const char xen_hypervisor_callback[];
 extern const char xen_failsafe_callback[];
 
-unsigned long *phys_to_machine_mapping;
-EXPORT_SYMBOL(phys_to_machine_mapping);
 
 /**
  * machine_specific_memory_setup - Hook for machine specific memory setup.
@@ -38,9 +38,31 @@ char * __init xen_memory_setup(void)
 {
        unsigned long max_pfn = xen_start_info->nr_pages;
 
+       max_pfn = min(MAX_DOMAIN_PAGES, max_pfn);
+
        e820.nr_map = 0;
-       add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-       add_memory_region(HIGH_MEMORY, PFN_PHYS(max_pfn)-HIGH_MEMORY, E820_RAM);
+
+       e820_add_region(0, PFN_PHYS(max_pfn), E820_RAM);
+
+       /*
+        * Even though this is normal, usable memory under Xen, reserve
+        * ISA memory anyway because too many things think they can poke
+        * about in there.
+        */
+       e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS,
+                       E820_RESERVED);
+
+       /*
+        * Reserve Xen bits:
+        *  - mfn_list
+        *  - 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);
+
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 
        return "Xen";
 }
index 94e69000f9826e80da488a694477ee329998d230..d2e3c20127d7608fd0bb5735256994bb56fd01b2 100644 (file)
@@ -35,7 +35,7 @@
 #include "xen-ops.h"
 #include "mmu.h"
 
-static cpumask_t xen_cpu_initialized_map;
+cpumask_t xen_cpu_initialized_map;
 static DEFINE_PER_CPU(int, resched_irq) = -1;
 static DEFINE_PER_CPU(int, callfunc_irq) = -1;
 static DEFINE_PER_CPU(int, debug_irq) = -1;
@@ -65,6 +65,12 @@ static struct call_data_struct *call_data;
  */
 static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
 {
+#ifdef CONFIG_X86_32
+       __get_cpu_var(irq_stat).irq_resched_count++;
+#else
+       add_pda(irq_resched_count, 1);
+#endif
+
        return IRQ_HANDLED;
 }
 
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
new file mode 100644 (file)
index 0000000..251669a
--- /dev/null
@@ -0,0 +1,45 @@
+#include <linux/types.h>
+
+#include <xen/interface/xen.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/page.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+
+void xen_pre_suspend(void)
+{
+       xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
+       xen_start_info->console.domU.mfn =
+               mfn_to_pfn(xen_start_info->console.domU.mfn);
+
+       BUG_ON(!irqs_disabled());
+
+       HYPERVISOR_shared_info = &xen_dummy_shared_info;
+       if (HYPERVISOR_update_va_mapping(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
+                                        __pte_ma(0), 0))
+               BUG();
+}
+
+void xen_post_suspend(int suspend_cancelled)
+{
+       xen_setup_shared_info();
+
+       if (suspend_cancelled) {
+               xen_start_info->store_mfn =
+                       pfn_to_mfn(xen_start_info->store_mfn);
+               xen_start_info->console.domU.mfn =
+                       pfn_to_mfn(xen_start_info->console.domU.mfn);
+       } else {
+#ifdef CONFIG_SMP
+               xen_cpu_initialized_map = cpu_online_map;
+#endif
+               xen_vcpu_restore();
+               xen_timer_resume();
+       }
+
+}
+
index 41e217503c96552868d7d350711aaabaeff54d24..685b77470fc3612c45549018303808cb5cf628f3 100644 (file)
@@ -197,8 +197,8 @@ unsigned long long xen_sched_clock(void)
 }
 
 
-/* Get the CPU speed from Xen */
-unsigned long xen_cpu_khz(void)
+/* Get the TSC speed from Xen */
+unsigned long xen_tsc_khz(void)
 {
        u64 xen_khz = 1000000ULL << 32;
        const struct pvclock_vcpu_time_info *info =
@@ -459,6 +459,19 @@ void xen_setup_cpu_clockevents(void)
        clockevents_register_device(&__get_cpu_var(xen_clock_events));
 }
 
+void xen_timer_resume(void)
+{
+       int cpu;
+
+       if (xen_clockevent != &xen_vcpuop_clockevent)
+               return;
+
+       for_each_online_cpu(cpu) {
+               if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+                       BUG();
+       }
+}
+
 __init void xen_time_init(void)
 {
        int cpu = smp_processor_id();
index 6ec3b4f7719b411c630599d55251c81fb50f2ec3..7c0cf6320a0aa0ed55d56b5c627856dcb579d377 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <asm/boot.h>
 #include <xen/interface/elfnote.h>
+#include <asm/xen/interface.h>
 
        __INIT
 ENTRY(startup_xen)
@@ -32,5 +33,9 @@ ENTRY(hypercall_page)
        ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,       .asciz "!writable_page_tables|pae_pgdir_above_4gb")
        ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "yes")
        ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz "generic")
+       ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID,
+               .quad _PAGE_PRESENT; .quad _PAGE_PRESENT)
+       ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1)
+       ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW,   .long __HYPERVISOR_VIRT_START)
 
 #endif /*CONFIG_XEN */
index f1063ae0803795014d29af4a02ca9eb4211536b1..d852ddbb3448bf61245f4c16ecd88b8f14a2c5aa 100644 (file)
@@ -9,26 +9,35 @@
 extern const char xen_hypervisor_callback[];
 extern const char xen_failsafe_callback[];
 
+struct trap_info;
 void xen_copy_trap_info(struct trap_info *traps);
 
 DECLARE_PER_CPU(unsigned long, xen_cr3);
 DECLARE_PER_CPU(unsigned long, xen_current_cr3);
 
 extern struct start_info *xen_start_info;
+extern struct shared_info xen_dummy_shared_info;
 extern struct shared_info *HYPERVISOR_shared_info;
 
+void xen_setup_mfn_list_list(void);
+void xen_setup_shared_info(void);
+
 char * __init xen_memory_setup(void);
 void __init xen_arch_setup(void);
 void __init xen_init_IRQ(void);
 void xen_enable_sysenter(void);
+void xen_vcpu_restore(void);
+
+void __init xen_build_dynamic_phys_to_machine(void);
 
 void xen_setup_timer(int cpu);
 void xen_setup_cpu_clockevents(void);
-unsigned long xen_cpu_khz(void);
+unsigned long xen_tsc_khz(void);
 void __init xen_time_init(void);
 unsigned long xen_get_wallclock(void);
 int xen_set_wallclock(unsigned long time);
 unsigned long long xen_sched_clock(void);
+void xen_timer_resume(void);
 
 irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
 
@@ -54,6 +63,8 @@ int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
 int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
                               void *info, int wait);
 
+extern cpumask_t xen_cpu_initialized_map;
+
 
 /* Declare an asm function, along with symbols needed to make it
    inlineable */
index 3e97f2bc446f367fb8a3ffd28972d20a4176564f..1ab7c15c8d7a58bc2df639a759a0b719bb2c25da 100644 (file)
@@ -81,6 +81,18 @@ config BLK_DEV_BSG
 
          If unsure, say N.
 
+config BLK_DEV_INTEGRITY
+       bool "Block layer data integrity support"
+       ---help---
+       Some storage devices allow extra information to be
+       stored/retrieved to help protect the data.  The block layer
+       data integrity option provides hooks which can be used by
+       filesystems to ensure better data integrity.
+
+       Say yes here if you have a storage device that provides the
+       T10/SCSI Data Integrity Field or the T13/ATA External Path
+       Protection.  If in doubt, say N.
+
 endif # BLOCK
 
 config BLOCK_COMPAT
index 5a43c7d795942d1b478483e9464f1d58d471a15d..208000b0750d28589262daaaf819d5d6ff227105 100644 (file)
@@ -4,7 +4,8 @@
 
 obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \
-                       blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o
+                       blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o \
+                       cmd-filter.o
 
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
@@ -14,3 +15,4 @@ obj-$(CONFIG_IOSCHED_CFQ)     += cfq-iosched.o
 
 obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
 obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
+obj-$(CONFIG_BLK_DEV_INTEGRITY)        += blk-integrity.o
index 743f33a01a079166c503167038d3657f8850dadd..9735acb5b4f51544b831ecb07bd037f88d99090f 100644 (file)
@@ -151,6 +151,7 @@ enum arq_state {
 
 static DEFINE_PER_CPU(unsigned long, ioc_count);
 static struct completion *ioc_gone;
+static DEFINE_SPINLOCK(ioc_gone_lock);
 
 static void as_move_to_dispatch(struct as_data *ad, struct request *rq);
 static void as_antic_stop(struct as_data *ad);
@@ -164,8 +165,19 @@ static void free_as_io_context(struct as_io_context *aic)
 {
        kfree(aic);
        elv_ioc_count_dec(ioc_count);
-       if (ioc_gone && !elv_ioc_count_read(ioc_count))
-               complete(ioc_gone);
+       if (ioc_gone) {
+               /*
+                * AS scheduler is exiting, grab exit lock and check
+                * the pending io context count. If it hits zero,
+                * complete ioc_gone and set it back to NULL.
+                */
+               spin_lock(&ioc_gone_lock);
+               if (ioc_gone && !elv_ioc_count_read(ioc_count)) {
+                       complete(ioc_gone);
+                       ioc_gone = NULL;
+               }
+               spin_unlock(&ioc_gone_lock);
+       }
 }
 
 static void as_trim(struct io_context *ioc)
@@ -1493,7 +1505,7 @@ static void __exit as_exit(void)
        /* ioc_gone's update must be visible before reading ioc_count */
        smp_wmb();
        if (elv_ioc_count_read(ioc_count))
-               wait_for_completion(ioc_gone);
+               wait_for_completion(&all_gone);
        synchronize_rcu();
 }
 
index 1905aaba49fb2cd1d999bce222949c938fa3e9e5..dbc7f42b5d2bba5c252137923ec66d3beef482e1 100644 (file)
@@ -143,6 +143,10 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
 
                bio->bi_size -= nbytes;
                bio->bi_sector += (nbytes >> 9);
+
+               if (bio_integrity(bio))
+                       bio_integrity_advance(bio, nbytes);
+
                if (bio->bi_size == 0)
                        bio_endio(bio, error);
        } else {
@@ -201,8 +205,7 @@ void blk_plug_device(struct request_queue *q)
        if (blk_queue_stopped(q))
                return;
 
-       if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
-               __set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+       if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) {
                mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
                blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
        }
@@ -217,10 +220,9 @@ int blk_remove_plug(struct request_queue *q)
 {
        WARN_ON(!irqs_disabled());
 
-       if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+       if (!queue_flag_test_and_clear(QUEUE_FLAG_PLUGGED, q))
                return 0;
 
-       queue_flag_clear(QUEUE_FLAG_PLUGGED, q);
        del_timer(&q->unplug_timer);
        return 1;
 }
@@ -324,8 +326,7 @@ void blk_start_queue(struct request_queue *q)
         * one level of recursion is ok and is much faster than kicking
         * the unplug handling
         */
-       if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
-               queue_flag_set(QUEUE_FLAG_REENTER, q);
+       if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
                q->request_fn(q);
                queue_flag_clear(QUEUE_FLAG_REENTER, q);
        } else {
@@ -390,8 +391,7 @@ void __blk_run_queue(struct request_queue *q)
         * handling reinvoke the handler shortly if we already got there.
         */
        if (!elv_queue_empty(q)) {
-               if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
-                       queue_flag_set(QUEUE_FLAG_REENTER, q);
+               if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
                        q->request_fn(q);
                        queue_flag_clear(QUEUE_FLAG_REENTER, q);
                } else {
@@ -1381,6 +1381,9 @@ end_io:
                 */
                blk_partition_remap(bio);
 
+               if (bio_integrity_enabled(bio) && bio_integrity_prep(bio))
+                       goto end_io;
+
                if (old_sector != -1)
                        blk_add_trace_remap(q, bio, old_dev, bio->bi_sector,
                                            old_sector);
diff --git a/block/blk-integrity.c b/block/blk-integrity.c
new file mode 100644 (file)
index 0000000..3f1a847
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * blk-integrity.c - Block layer data integrity extensions
+ *
+ * Copyright (C) 2007, 2008 Oracle Corporation
+ * Written by: Martin K. Petersen <martin.petersen@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ */
+
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/bio.h>
+#include <linux/scatterlist.h>
+
+#include "blk.h"
+
+static struct kmem_cache *integrity_cachep;
+
+/**
+ * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
+ * @rq:                request with integrity metadata attached
+ *
+ * Description: Returns the number of elements required in a
+ * scatterlist corresponding to the integrity metadata in a request.
+ */
+int blk_rq_count_integrity_sg(struct request *rq)
+{
+       struct bio_vec *iv, *ivprv;
+       struct req_iterator iter;
+       unsigned int segments;
+
+       ivprv = NULL;
+       segments = 0;
+
+       rq_for_each_integrity_segment(iv, rq, iter) {
+
+               if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv))
+                       segments++;
+
+               ivprv = iv;
+       }
+
+       return segments;
+}
+EXPORT_SYMBOL(blk_rq_count_integrity_sg);
+
+/**
+ * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
+ * @rq:                request with integrity metadata attached
+ * @sglist:    target scatterlist
+ *
+ * Description: Map the integrity vectors in request into a
+ * scatterlist.  The scatterlist must be big enough to hold all
+ * elements.  I.e. sized using blk_rq_count_integrity_sg().
+ */
+int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist)
+{
+       struct bio_vec *iv, *ivprv;
+       struct req_iterator iter;
+       struct scatterlist *sg;
+       unsigned int segments;
+
+       ivprv = NULL;
+       sg = NULL;
+       segments = 0;
+
+       rq_for_each_integrity_segment(iv, rq, iter) {
+
+               if (ivprv) {
+                       if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
+                               goto new_segment;
+
+                       sg->length += iv->bv_len;
+               } else {
+new_segment:
+                       if (!sg)
+                               sg = sglist;
+                       else {
+                               sg->page_link &= ~0x02;
+                               sg = sg_next(sg);
+                       }
+
+                       sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset);
+                       segments++;
+               }
+
+               ivprv = iv;
+       }
+
+       if (sg)
+               sg_mark_end(sg);
+
+       return segments;
+}
+EXPORT_SYMBOL(blk_rq_map_integrity_sg);
+
+/**
+ * blk_integrity_compare - Compare integrity profile of two block devices
+ * @b1:                Device to compare
+ * @b2:                Device to compare
+ *
+ * Description: Meta-devices like DM and MD need to verify that all
+ * sub-devices use the same integrity format before advertising to
+ * upper layers that they can send/receive integrity metadata.  This
+ * function can be used to check whether two block devices have
+ * compatible integrity formats.
+ */
+int blk_integrity_compare(struct block_device *bd1, struct block_device *bd2)
+{
+       struct blk_integrity *b1 = bd1->bd_disk->integrity;
+       struct blk_integrity *b2 = bd2->bd_disk->integrity;
+
+       BUG_ON(bd1->bd_disk == NULL);
+       BUG_ON(bd2->bd_disk == NULL);
+
+       if (!b1 || !b2)
+               return 0;
+
+       if (b1->sector_size != b2->sector_size) {
+               printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__,
+                      bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+                      b1->sector_size, b2->sector_size);
+               return -1;
+       }
+
+       if (b1->tuple_size != b2->tuple_size) {
+               printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__,
+                      bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+                      b1->tuple_size, b2->tuple_size);
+               return -1;
+       }
+
+       if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
+               printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__,
+                      bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+                      b1->tag_size, b2->tag_size);
+               return -1;
+       }
+
+       if (strcmp(b1->name, b2->name)) {
+               printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__,
+                      bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
+                      b1->name, b2->name);
+               return -1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(blk_integrity_compare);
+
+struct integrity_sysfs_entry {
+       struct attribute attr;
+       ssize_t (*show)(struct blk_integrity *, char *);
+       ssize_t (*store)(struct blk_integrity *, const char *, size_t);
+};
+
+static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr,
+                                  char *page)
+{
+       struct blk_integrity *bi =
+               container_of(kobj, struct blk_integrity, kobj);
+       struct integrity_sysfs_entry *entry =
+               container_of(attr, struct integrity_sysfs_entry, attr);
+
+       return entry->show(bi, page);
+}
+
+static ssize_t integrity_attr_store(struct kobject *kobj,
+                                   struct attribute *attr, const char *page,
+                                   size_t count)
+{
+       struct blk_integrity *bi =
+               container_of(kobj, struct blk_integrity, kobj);
+       struct integrity_sysfs_entry *entry =
+               container_of(attr, struct integrity_sysfs_entry, attr);
+       ssize_t ret = 0;
+
+       if (entry->store)
+               ret = entry->store(bi, page, count);
+
+       return ret;
+}
+
+static ssize_t integrity_format_show(struct blk_integrity *bi, char *page)
+{
+       if (bi != NULL && bi->name != NULL)
+               return sprintf(page, "%s\n", bi->name);
+       else
+               return sprintf(page, "none\n");
+}
+
+static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page)
+{
+       if (bi != NULL)
+               return sprintf(page, "%u\n", bi->tag_size);
+       else
+               return sprintf(page, "0\n");
+}
+
+static ssize_t integrity_read_store(struct blk_integrity *bi,
+                                   const char *page, size_t count)
+{
+       char *p = (char *) page;
+       unsigned long val = simple_strtoul(p, &p, 10);
+
+       if (val)
+               bi->flags |= INTEGRITY_FLAG_READ;
+       else
+               bi->flags &= ~INTEGRITY_FLAG_READ;
+
+       return count;
+}
+
+static ssize_t integrity_read_show(struct blk_integrity *bi, char *page)
+{
+       return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_READ) != 0);
+}
+
+static ssize_t integrity_write_store(struct blk_integrity *bi,
+                                    const char *page, size_t count)
+{
+       char *p = (char *) page;
+       unsigned long val = simple_strtoul(p, &p, 10);
+
+       if (val)
+               bi->flags |= INTEGRITY_FLAG_WRITE;
+       else
+               bi->flags &= ~INTEGRITY_FLAG_WRITE;
+
+       return count;
+}
+
+static ssize_t integrity_write_show(struct blk_integrity *bi, char *page)
+{
+       return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_WRITE) != 0);
+}
+
+static struct integrity_sysfs_entry integrity_format_entry = {
+       .attr = { .name = "format", .mode = S_IRUGO },
+       .show = integrity_format_show,
+};
+
+static struct integrity_sysfs_entry integrity_tag_size_entry = {
+       .attr = { .name = "tag_size", .mode = S_IRUGO },
+       .show = integrity_tag_size_show,
+};
+
+static struct integrity_sysfs_entry integrity_read_entry = {
+       .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR },
+       .show = integrity_read_show,
+       .store = integrity_read_store,
+};
+
+static struct integrity_sysfs_entry integrity_write_entry = {
+       .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR },
+       .show = integrity_write_show,
+       .store = integrity_write_store,
+};
+
+static struct attribute *integrity_attrs[] = {
+       &integrity_format_entry.attr,
+       &integrity_tag_size_entry.attr,
+       &integrity_read_entry.attr,
+       &integrity_write_entry.attr,
+       NULL,
+};
+
+static struct sysfs_ops integrity_ops = {
+       .show   = &integrity_attr_show,
+       .store  = &integrity_attr_store,
+};
+
+static int __init blk_dev_integrity_init(void)
+{
+       integrity_cachep = kmem_cache_create("blkdev_integrity",
+                                            sizeof(struct blk_integrity),
+                                            0, SLAB_PANIC, NULL);
+       return 0;
+}
+subsys_initcall(blk_dev_integrity_init);
+
+static void blk_integrity_release(struct kobject *kobj)
+{
+       struct blk_integrity *bi =
+               container_of(kobj, struct blk_integrity, kobj);
+
+       kmem_cache_free(integrity_cachep, bi);
+}
+
+static struct kobj_type integrity_ktype = {
+       .default_attrs  = integrity_attrs,
+       .sysfs_ops      = &integrity_ops,
+       .release        = blk_integrity_release,
+};
+
+/**
+ * blk_integrity_register - Register a gendisk as being integrity-capable
+ * @disk:      struct gendisk pointer to make integrity-aware
+ * @template:  integrity profile
+ *
+ * Description: When a device needs to advertise itself as being able
+ * to send/receive integrity metadata it must use this function to
+ * register the capability with the block layer.  The template is a
+ * blk_integrity struct with values appropriate for the underlying
+ * hardware.  See Documentation/block/data-integrity.txt.
+ */
+int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
+{
+       struct blk_integrity *bi;
+
+       BUG_ON(disk == NULL);
+       BUG_ON(template == NULL);
+
+       if (disk->integrity == NULL) {
+               bi = kmem_cache_alloc(integrity_cachep,
+                                               GFP_KERNEL | __GFP_ZERO);
+               if (!bi)
+                       return -1;
+
+               if (kobject_init_and_add(&bi->kobj, &integrity_ktype,
+                                        &disk->dev.kobj, "%s", "integrity")) {
+                       kmem_cache_free(integrity_cachep, bi);
+                       return -1;
+               }
+
+               kobject_uevent(&bi->kobj, KOBJ_ADD);
+
+               bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE;
+               bi->sector_size = disk->queue->hardsect_size;
+               disk->integrity = bi;
+       } else
+               bi = disk->integrity;
+
+       /* Use the provided profile as template */
+       bi->name = template->name;
+       bi->generate_fn = template->generate_fn;
+       bi->verify_fn = template->verify_fn;
+       bi->tuple_size = template->tuple_size;
+       bi->set_tag_fn = template->set_tag_fn;
+       bi->get_tag_fn = template->get_tag_fn;
+       bi->tag_size = template->tag_size;
+
+       return 0;
+}
+EXPORT_SYMBOL(blk_integrity_register);
+
+/**
+ * blk_integrity_unregister - Remove block integrity profile
+ * @disk:      disk whose integrity profile to deallocate
+ *
+ * Description: This function frees all memory used by the block
+ * integrity profile.  To be called at device teardown.
+ */
+void blk_integrity_unregister(struct gendisk *disk)
+{
+       struct blk_integrity *bi;
+
+       if (!disk || !disk->integrity)
+               return;
+
+       bi = disk->integrity;
+
+       kobject_uevent(&bi->kobj, KOBJ_REMOVE);
+       kobject_del(&bi->kobj);
+       kobject_put(&disk->dev.kobj);
+       kmem_cache_free(integrity_cachep, bi);
+}
+EXPORT_SYMBOL(blk_integrity_unregister);
index 0b1af5a3537ca0728407c8acfedfaba44338cd19..ddd96fb11a7d71638a32e3e9060aac1f1adac808 100644 (file)
@@ -210,6 +210,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        if (!bio_flagged(bio, BIO_USER_MAPPED))
                rq->cmd_flags |= REQ_COPY_USER;
 
+       blk_queue_bounce(q, &bio);
        bio_get(bio);
        blk_rq_bio_prep(q, rq, bio);
        rq->buffer = rq->data = NULL;
@@ -268,6 +269,7 @@ 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;
+       unsigned long stack_mask = ~(THREAD_SIZE - 1);
 
        if (len > (q->max_hw_sectors << 9))
                return -EINVAL;
@@ -278,6 +280,10 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        alignment = queue_dma_alignment(q) | q->dma_pad_mask;
        do_copy = ((kaddr & alignment) || (len & alignment));
 
+       if (!((kaddr & stack_mask) ^
+             ((unsigned long)current->stack & stack_mask)))
+               do_copy = 1;
+
        if (do_copy)
                bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading);
        else
index 651136aae76e45ba821205a830a919a3d6d105c5..5efc9e7a68b777fe42cc53b2a7bf3add00adff2a 100644 (file)
@@ -441,6 +441,9 @@ static int attempt_merge(struct request_queue *q, struct request *req,
            || next->special)
                return 0;
 
+       if (blk_integrity_rq(req) != blk_integrity_rq(next))
+               return 0;
+
        /*
         * If we are allowed to merge, then append bio list
         * from next to rq and release next. merge_requests_fn
index 8dd86418f35d88229fdebc890e28cbfb62705c55..dfc77012843ffbf9e67fa8996d40099f2db667fe 100644 (file)
@@ -302,11 +302,10 @@ EXPORT_SYMBOL(blk_queue_stack_limits);
  * @q:     the request queue for the device
  * @mask:  pad mask
  *
- * Set pad mask.  Direct IO requests are padded to the mask specified.
+ * Set dma pad mask.
  *
- * Appending pad buffer to a request modifies ->data_len such that it
- * includes the pad buffer.  The original requested data length can be
- * obtained using blk_rq_raw_data_len().
+ * Appending pad buffer to a request modifies the last entry of a
+ * scatter list such that it includes the pad buffer.
  **/
 void blk_queue_dma_pad(struct request_queue *q, unsigned int mask)
 {
@@ -314,6 +313,23 @@ void blk_queue_dma_pad(struct request_queue *q, unsigned int mask)
 }
 EXPORT_SYMBOL(blk_queue_dma_pad);
 
+/**
+ * blk_queue_update_dma_pad - update pad mask
+ * @q:     the request queue for the device
+ * @mask:  pad mask
+ *
+ * Update dma pad mask.
+ *
+ * Appending pad buffer to a request modifies the last entry of a
+ * scatter list such that it includes the pad buffer.
+ **/
+void blk_queue_update_dma_pad(struct request_queue *q, unsigned int mask)
+{
+       if (mask > q->dma_pad_mask)
+               q->dma_pad_mask = mask;
+}
+EXPORT_SYMBOL(blk_queue_update_dma_pad);
+
 /**
  * blk_queue_dma_drain - Set up a drain buffer for excess dma.
  * @q:  the request queue for the device
index 59776ab4742aae29678d34886665dc437dadd00c..c79f30e1df52d8388c6c89505e97756f2f906098 100644 (file)
@@ -51,4 +51,12 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)
        return q->nr_congestion_off;
 }
 
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+
+#define rq_for_each_integrity_segment(bvl, _rq, _iter)         \
+       __rq_for_each_bio(_iter.bio, _rq)                       \
+               bip_for_each_vec(bvl, _iter.bio->bi_integrity, _iter.i)
+
+#endif /* BLK_DEV_INTEGRITY */
+
 #endif
index 8d3a277802603dd89c252784ea94f8dcc2d4b6d1..eb9651ccb241c28ce666300c02830ffea65df691 100644 (file)
@@ -244,6 +244,7 @@ err:
 static void blk_trace_cleanup(struct blk_trace *bt)
 {
        relay_close(bt->rchan);
+       debugfs_remove(bt->msg_file);
        debugfs_remove(bt->dropped_file);
        blk_remove_tree(bt->dir);
        free_percpu(bt->sequence);
@@ -291,6 +292,44 @@ static const struct file_operations blk_dropped_fops = {
        .read =         blk_dropped_read,
 };
 
+static int blk_msg_open(struct inode *inode, struct file *filp)
+{
+       filp->private_data = inode->i_private;
+
+       return 0;
+}
+
+static ssize_t blk_msg_write(struct file *filp, const char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       char *msg;
+       struct blk_trace *bt;
+
+       if (count > BLK_TN_MAX_MSG)
+               return -EINVAL;
+
+       msg = kmalloc(count, GFP_KERNEL);
+       if (msg == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(msg, buffer, count)) {
+               kfree(msg);
+               return -EFAULT;
+       }
+
+       bt = filp->private_data;
+       __trace_note_message(bt, "%s", msg);
+       kfree(msg);
+
+       return count;
+}
+
+static const struct file_operations blk_msg_fops = {
+       .owner =        THIS_MODULE,
+       .open =         blk_msg_open,
+       .write =        blk_msg_write,
+};
+
 /*
  * Keep track of how many times we encountered a full subbuffer, to aid
  * the user space app in telling how many lost events there were.
@@ -380,6 +419,10 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        if (!bt->dropped_file)
                goto err;
 
+       bt->msg_file = debugfs_create_file("msg", 0222, dir, bt, &blk_msg_fops);
+       if (!bt->msg_file)
+               goto err;
+
        bt->rchan = relay_open("trace", dir, buts->buf_size,
                                buts->buf_nr, &blk_relay_callbacks, bt);
        if (!bt->rchan)
@@ -409,6 +452,8 @@ err:
        if (dir)
                blk_remove_tree(dir);
        if (bt) {
+               if (bt->msg_file)
+                       debugfs_remove(bt->msg_file);
                if (bt->dropped_file)
                        debugfs_remove(bt->dropped_file);
                free_percpu(bt->sequence);
index 54d617f7df3e03b3aa02def2473b03ad66a5d39b..93e757d7174b8b7a5ff6aeaee124915bfda5ccf7 100644 (file)
@@ -44,11 +44,12 @@ struct bsg_device {
        char name[BUS_ID_SIZE];
        int max_queue;
        unsigned long flags;
+       struct blk_scsi_cmd_filter *cmd_filter;
+       mode_t *f_mode;
 };
 
 enum {
        BSG_F_BLOCK             = 1,
-       BSG_F_WRITE_PERM        = 2,
 };
 
 #define BSG_DEFAULT_CMDS       64
@@ -172,7 +173,7 @@ unlock:
 }
 
 static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
-                               struct sg_io_v4 *hdr, int has_write_perm)
+                               struct sg_io_v4 *hdr, struct bsg_device *bd)
 {
        if (hdr->request_len > BLK_MAX_CDB) {
                rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
@@ -185,7 +186,8 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
                return -EFAULT;
 
        if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
-               if (blk_verify_command(rq->cmd, has_write_perm))
+               if (blk_cmd_filter_verify_command(bd->cmd_filter, rq->cmd,
+                                                bd->f_mode))
                        return -EPERM;
        } else if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
@@ -263,8 +265,7 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
        rq = blk_get_request(q, rw, GFP_KERNEL);
        if (!rq)
                return ERR_PTR(-ENOMEM);
-       ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM,
-                                                      &bd->flags));
+       ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd);
        if (ret)
                goto out;
 
@@ -566,12 +567,23 @@ static inline void bsg_set_block(struct bsg_device *bd, struct file *file)
                set_bit(BSG_F_BLOCK, &bd->flags);
 }
 
-static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file)
+static void bsg_set_cmd_filter(struct bsg_device *bd,
+                          struct file *file)
 {
-       if (file->f_mode & FMODE_WRITE)
-               set_bit(BSG_F_WRITE_PERM, &bd->flags);
-       else
-               clear_bit(BSG_F_WRITE_PERM, &bd->flags);
+       struct inode *inode;
+       struct gendisk *disk;
+
+       if (!file)
+               return;
+
+       inode = file->f_dentry->d_inode;
+       if (!inode)
+               return;
+
+       disk = inode->i_bdev->bd_disk;
+
+       bd->cmd_filter = &disk->cmd_filter;
+       bd->f_mode = &file->f_mode;
 }
 
 /*
@@ -595,6 +607,8 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        dprintk("%s: read %Zd bytes\n", bd->name, count);
 
        bsg_set_block(bd, file);
+       bsg_set_cmd_filter(bd, file);
+
        bytes_read = 0;
        ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
        *ppos = bytes_read;
@@ -668,7 +682,7 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
        dprintk("%s: write %Zd bytes\n", bd->name, count);
 
        bsg_set_block(bd, file);
-       bsg_set_write_perm(bd, file);
+       bsg_set_cmd_filter(bd, file);
 
        bytes_written = 0;
        ret = __bsg_write(bd, buf, count, &bytes_written);
@@ -772,7 +786,9 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
        }
 
        bd->queue = rq;
+
        bsg_set_block(bd, file);
+       bsg_set_cmd_filter(bd, file);
 
        atomic_set(&bd->ref_count, 1);
        mutex_lock(&bsg_mutex);
index d01b411c72f053225c2faee733e4299afeeec51b..1e2aff812ee2b278bd831809269c4d6c76234858 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/elevator.h>
 #include <linux/rbtree.h>
 #include <linux/ioprio.h>
+#include <linux/blktrace_api.h>
 
 /*
  * tunables
@@ -41,13 +42,14 @@ static int cfq_slice_idle = HZ / 125;
 
 #define RQ_CIC(rq)             \
        ((struct cfq_io_context *) (rq)->elevator_private)
-#define RQ_CFQQ(rq)            ((rq)->elevator_private2)
+#define RQ_CFQQ(rq)            (struct cfq_queue *) ((rq)->elevator_private2)
 
 static struct kmem_cache *cfq_pool;
 static struct kmem_cache *cfq_ioc_pool;
 
 static DEFINE_PER_CPU(unsigned long, ioc_count);
 static struct completion *ioc_gone;
+static DEFINE_SPINLOCK(ioc_gone_lock);
 
 #define CFQ_PRIO_LISTS         IOPRIO_BE_NR
 #define cfq_class_idle(cfqq)   ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
@@ -155,6 +157,7 @@ struct cfq_queue {
        unsigned short ioprio, org_ioprio;
        unsigned short ioprio_class, org_ioprio_class;
 
+       pid_t pid;
 };
 
 enum cfqq_state_flags {
@@ -198,6 +201,11 @@ CFQ_CFQQ_FNS(slice_new);
 CFQ_CFQQ_FNS(sync);
 #undef CFQ_CFQQ_FNS
 
+#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
+       blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args)
+#define cfq_log(cfqd, fmt, args...)    \
+       blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args)
+
 static void cfq_dispatch_insert(struct request_queue *, struct request *);
 static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
                                       struct io_context *, gfp_t);
@@ -234,8 +242,10 @@ static inline int cfq_bio_sync(struct bio *bio)
  */
 static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
 {
-       if (cfqd->busy_queues)
+       if (cfqd->busy_queues) {
+               cfq_log(cfqd, "schedule dispatch");
                kblockd_schedule_work(&cfqd->unplug_work);
+       }
 }
 
 static int cfq_queue_empty(struct request_queue *q)
@@ -270,6 +280,7 @@ static inline void
 cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+       cfq_log_cfqq(cfqd, cfqq, "set_slice=%lu", cfqq->slice_end - jiffies);
 }
 
 /*
@@ -539,6 +550,7 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
  */
 static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+       cfq_log_cfqq(cfqd, cfqq, "add_to_rr");
        BUG_ON(cfq_cfqq_on_rr(cfqq));
        cfq_mark_cfqq_on_rr(cfqq);
        cfqd->busy_queues++;
@@ -552,6 +564,7 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
  */
 static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+       cfq_log_cfqq(cfqd, cfqq, "del_from_rr");
        BUG_ON(!cfq_cfqq_on_rr(cfqq));
        cfq_clear_cfqq_on_rr(cfqq);
 
@@ -638,6 +651,8 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq)
        struct cfq_data *cfqd = q->elevator->elevator_data;
 
        cfqd->rq_in_driver++;
+       cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d",
+                                               cfqd->rq_in_driver);
 
        /*
         * If the depth is larger 1, it really could be queueing. But lets
@@ -657,6 +672,8 @@ static void cfq_deactivate_request(struct request_queue *q, struct request *rq)
 
        WARN_ON(!cfqd->rq_in_driver);
        cfqd->rq_in_driver--;
+       cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d",
+                                               cfqd->rq_in_driver);
 }
 
 static void cfq_remove_request(struct request *rq)
@@ -746,6 +763,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
                                   struct cfq_queue *cfqq)
 {
        if (cfqq) {
+               cfq_log_cfqq(cfqd, cfqq, "set_active");
                cfqq->slice_end = 0;
                cfq_clear_cfqq_must_alloc_slice(cfqq);
                cfq_clear_cfqq_fifo_expire(cfqq);
@@ -763,6 +781,8 @@ static void
 __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                    int timed_out)
 {
+       cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out);
+
        if (cfq_cfqq_wait_request(cfqq))
                del_timer(&cfqd->idle_slice_timer);
 
@@ -772,8 +792,10 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        /*
         * store what was left of this slice, if the queue idled/timed out
         */
-       if (timed_out && !cfq_cfqq_slice_new(cfqq))
+       if (timed_out && !cfq_cfqq_slice_new(cfqq)) {
                cfqq->slice_resid = cfqq->slice_end - jiffies;
+               cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
+       }
 
        cfq_resort_rr_list(cfqd, cfqq);
 
@@ -865,6 +887,12 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
        if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
                return;
 
+       /*
+        * still requests with the driver, don't idle
+        */
+       if (cfqd->rq_in_driver)
+               return;
+
        /*
         * task has exited, don't wait
         */
@@ -892,6 +920,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
                sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT));
 
        mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
+       cfq_log(cfqd, "arm_idle: %lu", sl);
 }
 
 /*
@@ -902,6 +931,8 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
 
+       cfq_log_cfqq(cfqd, cfqq, "dispatch_insert");
+
        cfq_remove_request(rq);
        cfqq->dispatched++;
        elv_dispatch_sort(q, rq);
@@ -931,8 +962,9 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
        rq = rq_entry_fifo(cfqq->fifo.next);
 
        if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
-               return NULL;
+               rq = NULL;
 
+       cfq_log_cfqq(cfqd, cfqq, "fifo=%p", rq);
        return rq;
 }
 
@@ -1072,6 +1104,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
 
        BUG_ON(cfqd->busy_queues);
 
+       cfq_log(cfqd, "forced_dispatch=%d\n", dispatched);
        return dispatched;
 }
 
@@ -1112,6 +1145,7 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
                dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
        }
 
+       cfq_log(cfqd, "dispatched=%d", dispatched);
        return dispatched;
 }
 
@@ -1130,6 +1164,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        if (!atomic_dec_and_test(&cfqq->ref))
                return;
 
+       cfq_log_cfqq(cfqd, cfqq, "put_queue");
        BUG_ON(rb_first(&cfqq->sort_list));
        BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
        BUG_ON(cfq_cfqq_on_rr(cfqq));
@@ -1177,8 +1212,19 @@ static void cfq_cic_free_rcu(struct rcu_head *head)
        kmem_cache_free(cfq_ioc_pool, cic);
        elv_ioc_count_dec(ioc_count);
 
-       if (ioc_gone && !elv_ioc_count_read(ioc_count))
-               complete(ioc_gone);
+       if (ioc_gone) {
+               /*
+                * CFQ scheduler is exiting, grab exit lock and check
+                * the pending io context count. If it hits zero,
+                * complete ioc_gone and set it back to NULL
+                */
+               spin_lock(&ioc_gone_lock);
+               if (ioc_gone && !elv_ioc_count_read(ioc_count)) {
+                       complete(ioc_gone);
+                       ioc_gone = NULL;
+               }
+               spin_unlock(&ioc_gone_lock);
+       }
 }
 
 static void cfq_cic_free(struct cfq_io_context *cic)
@@ -1427,6 +1473,8 @@ retry:
                                cfq_mark_cfqq_idle_window(cfqq);
                        cfq_mark_cfqq_sync(cfqq);
                }
+               cfqq->pid = current->pid;
+               cfq_log_cfqq(cfqd, cfqq, "alloced");
        }
 
        if (new_cfqq)
@@ -1675,7 +1723,7 @@ static void
 cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                       struct cfq_io_context *cic)
 {
-       int enable_idle;
+       int old_idle, enable_idle;
 
        /*
         * Don't idle for async or idle io prio class
@@ -1683,7 +1731,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq))
                return;
 
-       enable_idle = cfq_cfqq_idle_window(cfqq);
+       enable_idle = old_idle = cfq_cfqq_idle_window(cfqq);
 
        if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
            (cfqd->hw_tag && CIC_SEEKY(cic)))
@@ -1695,10 +1743,13 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                        enable_idle = 1;
        }
 
-       if (enable_idle)
-               cfq_mark_cfqq_idle_window(cfqq);
-       else
-               cfq_clear_cfqq_idle_window(cfqq);
+       if (old_idle != enable_idle) {
+               cfq_log_cfqq(cfqd, cfqq, "idle=%d", enable_idle);
+               if (enable_idle)
+                       cfq_mark_cfqq_idle_window(cfqq);
+               else
+                       cfq_clear_cfqq_idle_window(cfqq);
+       }
 }
 
 /*
@@ -1757,6 +1808,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
+       cfq_log_cfqq(cfqd, cfqq, "preempt");
        cfq_slice_expired(cfqd, 1);
 
        /*
@@ -1818,6 +1870,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
        struct cfq_data *cfqd = q->elevator->elevator_data;
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
 
+       cfq_log_cfqq(cfqd, cfqq, "insert_request");
        cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc);
 
        cfq_add_rq_rb(rq);
@@ -1835,6 +1888,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        unsigned long now;
 
        now = jiffies;
+       cfq_log_cfqq(cfqd, cfqq, "complete");
 
        WARN_ON(!cfqd->rq_in_driver);
        WARN_ON(!cfqq->dispatched);
@@ -2004,6 +2058,7 @@ queue_fail:
 
        cfq_schedule_dispatch(cfqd);
        spin_unlock_irqrestore(q->queue_lock, flags);
+       cfq_log(cfqd, "set_request fail");
        return 1;
 }
 
@@ -2029,6 +2084,8 @@ static void cfq_idle_slice_timer(unsigned long data)
        unsigned long flags;
        int timed_out = 1;
 
+       cfq_log(cfqd, "idle timer fired");
+
        spin_lock_irqsave(cfqd->queue->queue_lock, flags);
 
        cfqq = cfqd->active_queue;
@@ -2317,7 +2374,7 @@ static void __exit cfq_exit(void)
         * pending RCU callbacks
         */
        if (elv_ioc_count_read(ioc_count))
-               wait_for_completion(ioc_gone);
+               wait_for_completion(&all_gone);
        cfq_slab_kill();
 }
 
diff --git a/block/cmd-filter.c b/block/cmd-filter.c
new file mode 100644 (file)
index 0000000..eec4404
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2004 Peter M. Jones <pjones@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/genhd.h>
+#include <linux/spinlock.h>
+#include <linux/parser.h>
+#include <linux/capability.h>
+#include <linux/bitops.h>
+
+#include <scsi/scsi.h>
+#include <linux/cdrom.h>
+
+int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter,
+                                 unsigned char *cmd, mode_t *f_mode)
+{
+       /* root can do any command. */
+       if (capable(CAP_SYS_RAWIO))
+               return 0;
+
+       /* if there's no filter set, assume we're filtering everything out */
+       if (!filter)
+               return -EPERM;
+
+       /* Anybody who can open the device can do a read-safe command */
+       if (test_bit(cmd[0], filter->read_ok))
+               return 0;
+
+       /* Write-safe commands require a writable open */
+       if (test_bit(cmd[0], filter->write_ok) && (*f_mode & FMODE_WRITE))
+               return 0;
+
+       return -EPERM;
+}
+EXPORT_SYMBOL(blk_cmd_filter_verify_command);
+
+int blk_verify_command(struct file *file, unsigned char *cmd)
+{
+       struct gendisk *disk;
+       struct inode *inode;
+
+       if (!file)
+               return -EINVAL;
+
+       inode = file->f_dentry->d_inode;
+       if (!inode)
+               return -EINVAL;
+
+       disk = inode->i_bdev->bd_disk;
+
+       return blk_cmd_filter_verify_command(&disk->cmd_filter,
+                                                cmd, &file->f_mode);
+}
+EXPORT_SYMBOL(blk_verify_command);
+
+/* and now, the sysfs stuff */
+static ssize_t rcf_cmds_show(struct blk_scsi_cmd_filter *filter, char *page,
+                            int rw)
+{
+       char *npage = page;
+       unsigned long *okbits;
+       int i;
+
+       if (rw == READ)
+               okbits = filter->read_ok;
+       else
+               okbits = filter->write_ok;
+
+       for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) {
+               if (test_bit(i, okbits)) {
+                       sprintf(npage, "%02x", i);
+                       npage += 2;
+                       if (i < BLK_SCSI_MAX_CMDS - 1)
+                               sprintf(npage++, " ");
+               }
+       }
+
+       if (npage != page)
+               npage += sprintf(npage, "\n");
+
+       return npage - page;
+}
+
+static ssize_t rcf_readcmds_show(struct blk_scsi_cmd_filter *filter, char *page)
+{
+       return rcf_cmds_show(filter, page, READ);
+}
+
+static ssize_t rcf_writecmds_show(struct blk_scsi_cmd_filter *filter,
+                                char *page)
+{
+       return rcf_cmds_show(filter, page, WRITE);
+}
+
+static ssize_t rcf_cmds_store(struct blk_scsi_cmd_filter *filter,
+                             const char *page, size_t count, int rw)
+{
+       ssize_t ret = 0;
+       unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits;
+       int cmd, status, len;
+       substring_t ss;
+
+       memset(&okbits, 0, sizeof(okbits));
+
+       for (len = strlen(page); len > 0; len -= 3) {
+               if (len < 2)
+                       break;
+               ss.from = (char *) page + ret;
+               ss.to = (char *) page + ret + 2;
+               ret += 3;
+               status = match_hex(&ss, &cmd);
+               /* either of these cases means invalid input, so do nothing. */
+               if (status || cmd >= BLK_SCSI_MAX_CMDS)
+                       return -EINVAL;
+
+               __set_bit(cmd, okbits);
+       }
+
+       if (rw == READ)
+               target_okbits = filter->read_ok;
+       else
+               target_okbits = filter->write_ok;
+
+       memmove(target_okbits, okbits, sizeof(okbits));
+       return count;
+}
+
+static ssize_t rcf_readcmds_store(struct blk_scsi_cmd_filter *filter,
+                                 const char *page, size_t count)
+{
+       return rcf_cmds_store(filter, page, count, READ);
+}
+
+static ssize_t rcf_writecmds_store(struct blk_scsi_cmd_filter *filter,
+                                  const char *page, size_t count)
+{
+       return rcf_cmds_store(filter, page, count, WRITE);
+}
+
+struct rcf_sysfs_entry {
+       struct attribute attr;
+       ssize_t (*show)(struct blk_scsi_cmd_filter *, char *);
+       ssize_t (*store)(struct blk_scsi_cmd_filter *, const char *, size_t);
+};
+
+static struct rcf_sysfs_entry rcf_readcmds_entry = {
+       .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR },
+       .show = rcf_readcmds_show,
+       .store = rcf_readcmds_store,
+};
+
+static struct rcf_sysfs_entry rcf_writecmds_entry = {
+       .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR },
+       .show = rcf_writecmds_show,
+       .store = rcf_writecmds_store,
+};
+
+static struct attribute *default_attrs[] = {
+       &rcf_readcmds_entry.attr,
+       &rcf_writecmds_entry.attr,
+       NULL,
+};
+
+#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr)
+
+static ssize_t
+rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+       struct rcf_sysfs_entry *entry = to_rcf(attr);
+       struct blk_scsi_cmd_filter *filter;
+
+       filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj);
+       if (entry->show)
+               return entry->show(filter, page);
+
+       return 0;
+}
+
+static ssize_t
+rcf_attr_store(struct kobject *kobj, struct attribute *attr,
+                       const char *page, size_t length)
+{
+       struct rcf_sysfs_entry *entry = to_rcf(attr);
+       struct blk_scsi_cmd_filter *filter;
+
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       if (!entry->store)
+               return -EINVAL;
+
+       filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj);
+       return entry->store(filter, page, length);
+}
+
+static struct sysfs_ops rcf_sysfs_ops = {
+       .show = rcf_attr_show,
+       .store = rcf_attr_store,
+};
+
+static struct kobj_type rcf_ktype = {
+       .sysfs_ops = &rcf_sysfs_ops,
+       .default_attrs = default_attrs,
+};
+
+#ifndef MAINTENANCE_IN_CMD
+#define MAINTENANCE_IN_CMD 0xa3
+#endif
+
+static void rcf_set_defaults(struct blk_scsi_cmd_filter *filter)
+{
+       /* Basic read-only commands */
+       __set_bit(TEST_UNIT_READY, filter->read_ok);
+       __set_bit(REQUEST_SENSE, filter->read_ok);
+       __set_bit(READ_6, filter->read_ok);
+       __set_bit(READ_10, filter->read_ok);
+       __set_bit(READ_12, filter->read_ok);
+       __set_bit(READ_16, filter->read_ok);
+       __set_bit(READ_BUFFER, filter->read_ok);
+       __set_bit(READ_DEFECT_DATA, filter->read_ok);
+       __set_bit(READ_CAPACITY, filter->read_ok);
+       __set_bit(READ_LONG, filter->read_ok);
+       __set_bit(INQUIRY, filter->read_ok);
+       __set_bit(MODE_SENSE, filter->read_ok);
+       __set_bit(MODE_SENSE_10, filter->read_ok);
+       __set_bit(LOG_SENSE, filter->read_ok);
+       __set_bit(START_STOP, filter->read_ok);
+       __set_bit(GPCMD_VERIFY_10, filter->read_ok);
+       __set_bit(VERIFY_16, filter->read_ok);
+       __set_bit(REPORT_LUNS, filter->read_ok);
+       __set_bit(SERVICE_ACTION_IN, filter->read_ok);
+       __set_bit(RECEIVE_DIAGNOSTIC, filter->read_ok);
+       __set_bit(MAINTENANCE_IN_CMD, filter->read_ok);
+       __set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok);
+
+       /* Audio CD commands */
+       __set_bit(GPCMD_PLAY_CD, filter->read_ok);
+       __set_bit(GPCMD_PLAY_AUDIO_10, filter->read_ok);
+       __set_bit(GPCMD_PLAY_AUDIO_MSF, filter->read_ok);
+       __set_bit(GPCMD_PLAY_AUDIO_TI, filter->read_ok);
+       __set_bit(GPCMD_PAUSE_RESUME, filter->read_ok);
+
+       /* CD/DVD data reading */
+       __set_bit(GPCMD_READ_CD, filter->read_ok);
+       __set_bit(GPCMD_READ_CD_MSF, filter->read_ok);
+       __set_bit(GPCMD_READ_DISC_INFO, filter->read_ok);
+       __set_bit(GPCMD_READ_CDVD_CAPACITY, filter->read_ok);
+       __set_bit(GPCMD_READ_DVD_STRUCTURE, filter->read_ok);
+       __set_bit(GPCMD_READ_HEADER, filter->read_ok);
+       __set_bit(GPCMD_READ_TRACK_RZONE_INFO, filter->read_ok);
+       __set_bit(GPCMD_READ_SUBCHANNEL, filter->read_ok);
+       __set_bit(GPCMD_READ_TOC_PMA_ATIP, filter->read_ok);
+       __set_bit(GPCMD_REPORT_KEY, filter->read_ok);
+       __set_bit(GPCMD_SCAN, filter->read_ok);
+       __set_bit(GPCMD_GET_CONFIGURATION, filter->read_ok);
+       __set_bit(GPCMD_READ_FORMAT_CAPACITIES, filter->read_ok);
+       __set_bit(GPCMD_GET_EVENT_STATUS_NOTIFICATION, filter->read_ok);
+       __set_bit(GPCMD_GET_PERFORMANCE, filter->read_ok);
+       __set_bit(GPCMD_SEEK, filter->read_ok);
+       __set_bit(GPCMD_STOP_PLAY_SCAN, filter->read_ok);
+
+       /* Basic writing commands */
+       __set_bit(WRITE_6, filter->write_ok);
+       __set_bit(WRITE_10, filter->write_ok);
+       __set_bit(WRITE_VERIFY, filter->write_ok);
+       __set_bit(WRITE_12, filter->write_ok);
+       __set_bit(WRITE_VERIFY_12, filter->write_ok);
+       __set_bit(WRITE_16, filter->write_ok);
+       __set_bit(WRITE_LONG, filter->write_ok);
+       __set_bit(WRITE_LONG_2, filter->write_ok);
+       __set_bit(ERASE, filter->write_ok);
+       __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok);
+       __set_bit(MODE_SELECT, filter->write_ok);
+       __set_bit(LOG_SELECT, filter->write_ok);
+       __set_bit(GPCMD_BLANK, filter->write_ok);
+       __set_bit(GPCMD_CLOSE_TRACK, filter->write_ok);
+       __set_bit(GPCMD_FLUSH_CACHE, filter->write_ok);
+       __set_bit(GPCMD_FORMAT_UNIT, filter->write_ok);
+       __set_bit(GPCMD_REPAIR_RZONE_TRACK, filter->write_ok);
+       __set_bit(GPCMD_RESERVE_RZONE_TRACK, filter->write_ok);
+       __set_bit(GPCMD_SEND_DVD_STRUCTURE, filter->write_ok);
+       __set_bit(GPCMD_SEND_EVENT, filter->write_ok);
+       __set_bit(GPCMD_SEND_KEY, filter->write_ok);
+       __set_bit(GPCMD_SEND_OPC, filter->write_ok);
+       __set_bit(GPCMD_SEND_CUE_SHEET, filter->write_ok);
+       __set_bit(GPCMD_SET_SPEED, filter->write_ok);
+       __set_bit(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, filter->write_ok);
+       __set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok);
+       __set_bit(GPCMD_SET_STREAMING, filter->write_ok);
+}
+
+int blk_register_filter(struct gendisk *disk)
+{
+       int ret;
+       struct blk_scsi_cmd_filter *filter = &disk->cmd_filter;
+       struct kobject *parent = kobject_get(disk->holder_dir->parent);
+
+       if (!parent)
+               return -ENODEV;
+
+       ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, parent,
+                                "%s", "cmd_filter");
+
+       if (ret < 0)
+               return ret;
+
+       rcf_set_defaults(filter);
+       return 0;
+}
+
+void blk_unregister_filter(struct gendisk *disk)
+{
+       struct blk_scsi_cmd_filter *filter = &disk->cmd_filter;
+
+       kobject_put(&filter->kobj);
+       kobject_put(disk->holder_dir->parent);
+}
+
index 902dd1344d56dfb9000ba5701dbb250bcf835d27..ed6f8f32d27ee8d09f5c3673852d416bad228862 100644 (file)
@@ -86,6 +86,12 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
        if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special)
                return 0;
 
+       /*
+        * only merge integrity protected bio into ditto rq
+        */
+       if (bio_integrity(bio) != blk_integrity_rq(rq))
+               return 0;
+
        if (!elv_iosched_allow_merge(rq, bio))
                return 0;
 
@@ -144,7 +150,7 @@ static struct elevator_type *elevator_get(const char *name)
                else
                        sprintf(elv, "%s-iosched", name);
 
-               request_module(elv);
+               request_module("%s", elv);
                spin_lock(&elv_list_lock);
                e = elevator_find(name);
        }
index b922d4801c87d0f6951f86f8deae3fc32bbd03d7..9074f384b0970535c9048432065ef043ff231923 100644 (file)
@@ -189,6 +189,7 @@ void add_disk(struct gendisk *disk)
                            disk->minors, NULL, exact_match, exact_lock, disk);
        register_disk(disk);
        blk_register_queue(disk);
+       blk_register_filter(disk);
 
        bdi = &disk->queue->backing_dev_info;
        bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
@@ -200,6 +201,7 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */
 
 void unlink_gendisk(struct gendisk *disk)
 {
+       blk_unregister_filter(disk);
        sysfs_remove_link(&disk->dev.kobj, "bdi");
        bdi_unregister(&disk->queue->backing_dev_info);
        blk_unregister_queue(disk);
@@ -400,6 +402,14 @@ static ssize_t disk_removable_show(struct device *dev,
                       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
 }
 
+static ssize_t disk_ro_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%d\n", disk->policy ? 1 : 0);
+}
+
 static ssize_t disk_size_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
@@ -472,6 +482,7 @@ static ssize_t disk_fail_store(struct device *dev,
 
 static DEVICE_ATTR(range, S_IRUGO, disk_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, disk_size_show, NULL);
 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
@@ -483,6 +494,7 @@ static struct device_attribute dev_attr_fail =
 static struct attribute *disk_attrs[] = {
        &dev_attr_range.attr,
        &dev_attr_removable.attr,
+       &dev_attr_ro.attr,
        &dev_attr_size.attr,
        &dev_attr_capability.attr,
        &dev_attr_stat.attr,
index 78199c08ec92fc7c23549ef41c7d5b0862cfb938..c5b9bcfc0a6d9c3629fa1aa1492fbcba1cb42e32 100644 (file)
@@ -105,120 +105,12 @@ static int sg_emulated_host(struct request_queue *q, int __user *p)
        return put_user(1, p);
 }
 
-#define CMD_READ_SAFE  0x01
-#define CMD_WRITE_SAFE 0x02
-#define CMD_WARNED     0x04
-#define safe_for_read(cmd)     [cmd] = CMD_READ_SAFE
-#define safe_for_write(cmd)    [cmd] = CMD_WRITE_SAFE
-
-int blk_verify_command(unsigned char *cmd, int has_write_perm)
-{
-       static unsigned char cmd_type[256] = {
-
-               /* Basic read-only commands */
-               safe_for_read(TEST_UNIT_READY),
-               safe_for_read(REQUEST_SENSE),
-               safe_for_read(READ_6),
-               safe_for_read(READ_10),
-               safe_for_read(READ_12),
-               safe_for_read(READ_16),
-               safe_for_read(READ_BUFFER),
-               safe_for_read(READ_DEFECT_DATA),
-               safe_for_read(READ_LONG),
-               safe_for_read(INQUIRY),
-               safe_for_read(MODE_SENSE),
-               safe_for_read(MODE_SENSE_10),
-               safe_for_read(LOG_SENSE),
-               safe_for_read(START_STOP),
-               safe_for_read(GPCMD_VERIFY_10),
-               safe_for_read(VERIFY_16),
-
-               /* Audio CD commands */
-               safe_for_read(GPCMD_PLAY_CD),
-               safe_for_read(GPCMD_PLAY_AUDIO_10),
-               safe_for_read(GPCMD_PLAY_AUDIO_MSF),
-               safe_for_read(GPCMD_PLAY_AUDIO_TI),
-               safe_for_read(GPCMD_PAUSE_RESUME),
-
-               /* CD/DVD data reading */
-               safe_for_read(GPCMD_READ_BUFFER_CAPACITY),
-               safe_for_read(GPCMD_READ_CD),
-               safe_for_read(GPCMD_READ_CD_MSF),
-               safe_for_read(GPCMD_READ_DISC_INFO),
-               safe_for_read(GPCMD_READ_CDVD_CAPACITY),
-               safe_for_read(GPCMD_READ_DVD_STRUCTURE),
-               safe_for_read(GPCMD_READ_HEADER),
-               safe_for_read(GPCMD_READ_TRACK_RZONE_INFO),
-               safe_for_read(GPCMD_READ_SUBCHANNEL),
-               safe_for_read(GPCMD_READ_TOC_PMA_ATIP),
-               safe_for_read(GPCMD_REPORT_KEY),
-               safe_for_read(GPCMD_SCAN),
-               safe_for_read(GPCMD_GET_CONFIGURATION),
-               safe_for_read(GPCMD_READ_FORMAT_CAPACITIES),
-               safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION),
-               safe_for_read(GPCMD_GET_PERFORMANCE),
-               safe_for_read(GPCMD_SEEK),
-               safe_for_read(GPCMD_STOP_PLAY_SCAN),
-
-               /* Basic writing commands */
-               safe_for_write(WRITE_6),
-               safe_for_write(WRITE_10),
-               safe_for_write(WRITE_VERIFY),
-               safe_for_write(WRITE_12),
-               safe_for_write(WRITE_VERIFY_12),
-               safe_for_write(WRITE_16),
-               safe_for_write(WRITE_LONG),
-               safe_for_write(WRITE_LONG_2),
-               safe_for_write(ERASE),
-               safe_for_write(GPCMD_MODE_SELECT_10),
-               safe_for_write(MODE_SELECT),
-               safe_for_write(LOG_SELECT),
-               safe_for_write(GPCMD_BLANK),
-               safe_for_write(GPCMD_CLOSE_TRACK),
-               safe_for_write(GPCMD_FLUSH_CACHE),
-               safe_for_write(GPCMD_FORMAT_UNIT),
-               safe_for_write(GPCMD_REPAIR_RZONE_TRACK),
-               safe_for_write(GPCMD_RESERVE_RZONE_TRACK),
-               safe_for_write(GPCMD_SEND_DVD_STRUCTURE),
-               safe_for_write(GPCMD_SEND_EVENT),
-               safe_for_write(GPCMD_SEND_KEY),
-               safe_for_write(GPCMD_SEND_OPC),
-               safe_for_write(GPCMD_SEND_CUE_SHEET),
-               safe_for_write(GPCMD_SET_SPEED),
-               safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL),
-               safe_for_write(GPCMD_LOAD_UNLOAD),
-               safe_for_write(GPCMD_SET_STREAMING),
-       };
-       unsigned char type = cmd_type[cmd[0]];
-
-       /* Anybody who can open the device can do a read-safe command */
-       if (type & CMD_READ_SAFE)
-               return 0;
-
-       /* Write-safe commands just require a writable open.. */
-       if ((type & CMD_WRITE_SAFE) && has_write_perm)
-               return 0;
-
-       /* And root can do any command.. */
-       if (capable(CAP_SYS_RAWIO))
-               return 0;
-
-       if (!type) {
-               cmd_type[cmd[0]] = CMD_WARNED;
-               printk(KERN_WARNING "scsi: unknown opcode 0x%02x\n", cmd[0]);
-       }
-
-       /* Otherwise fail it with an "Operation not permitted" */
-       return -EPERM;
-}
-EXPORT_SYMBOL_GPL(blk_verify_command);
-
 static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
-                            struct sg_io_hdr *hdr, int has_write_perm)
+                            struct sg_io_hdr *hdr, struct file *file)
 {
        if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
                return -EFAULT;
-       if (blk_verify_command(rq->cmd, has_write_perm))
+       if (blk_verify_command(file, rq->cmd))
                return -EPERM;
 
        /*
@@ -287,7 +179,7 @@ static int sg_io(struct file *file, struct request_queue *q,
                struct gendisk *bd_disk, struct sg_io_hdr *hdr)
 {
        unsigned long start_time;
-       int writing = 0, ret = 0, has_write_perm = 0;
+       int writing = 0, ret = 0;
        struct request *rq;
        char sense[SCSI_SENSE_BUFFERSIZE];
        struct bio *bio;
@@ -316,10 +208,7 @@ static int sg_io(struct file *file, struct request_queue *q,
        if (!rq)
                return -ENOMEM;
 
-       if (file)
-               has_write_perm = file->f_mode & FMODE_WRITE;
-
-       if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) {
+       if (blk_fill_sghdr_rq(q, rq, hdr, file)) {
                blk_put_request(rq);
                return -EFAULT;
        }
@@ -451,7 +340,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
        if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
                goto error;
 
-       err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE);
+       err = blk_verify_command(file, rq->cmd);
        if (err)
                goto error;
 
index 864456c140fe7a6e2625527518c45eae75e20e4d..ea503572fcbead5497bce6aa5ed1c7de03fe6d77 100644 (file)
@@ -65,6 +65,7 @@ config CRYPTO_NULL
 config CRYPTO_CRYPTD
        tristate "Software async crypto daemon"
        select CRYPTO_BLKCIPHER
+       select CRYPTO_HASH
        select CRYPTO_MANAGER
        help
          This is a generic software asynchronous crypto daemon that
@@ -212,7 +213,7 @@ comment "Digest"
 
 config CRYPTO_CRC32C
        tristate "CRC32c CRC algorithm"
-       select CRYPTO_ALGAPI
+       select CRYPTO_HASH
        select LIBCRC32C
        help
          Castagnoli, et al Cyclic Redundancy-Check Algorithm.  Used
@@ -241,6 +242,57 @@ config CRYPTO_MICHAEL_MIC
          should not be used for other purposes because of the weakness
          of the algorithm.
 
+config CRYPTO_RMD128
+  tristate "RIPEMD-128 digest algorithm"
+  select CRYPTO_ALGAPI
+  help
+    RIPEMD-128 (ISO/IEC 10118-3:2004).
+
+    RIPEMD-128 is a 128-bit cryptographic hash function. It should only
+    to be used as a secure replacement for RIPEMD. For other use cases
+    RIPEMD-160 should be used.
+
+    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+
+config CRYPTO_RMD160
+  tristate "RIPEMD-160 digest algorithm"
+  select CRYPTO_ALGAPI
+  help
+    RIPEMD-160 (ISO/IEC 10118-3:2004).
+
+    RIPEMD-160 is a 160-bit cryptographic hash function. It is intended
+    to be used as a secure replacement for the 128-bit hash functions
+    MD4, MD5 and it's predecessor RIPEMD (not to be confused with RIPEMD-128).
+
+    It's speed is comparable to SHA1 and there are no known attacks against
+    RIPEMD-160.
+
+    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+
+config CRYPTO_RMD256
+  tristate "RIPEMD-256 digest algorithm"
+  select CRYPTO_ALGAPI
+  help
+    RIPEMD-256 is an optional extension of RIPEMD-128 with a 256 bit hash.
+    It is intended for applications that require longer hash-results, without
+    needing a larger security level (than RIPEMD-128).
+
+    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+
+config CRYPTO_RMD320
+  tristate "RIPEMD-320 digest algorithm"
+  select CRYPTO_ALGAPI
+  help
+    RIPEMD-320 is an optional extension of RIPEMD-160 with a 320 bit hash.
+    It is intended for applications that require longer hash-results, without
+    needing a larger security level (than RIPEMD-160).
+
+    Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
+    See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+
 config CRYPTO_SHA1
        tristate "SHA1 digest algorithm"
        select CRYPTO_ALGAPI
@@ -614,6 +666,15 @@ config CRYPTO_LZO
        help
          This is the LZO algorithm.
 
+comment "Random Number Generation"
+
+config CRYPTO_PRNG
+       tristate "Pseudo Random Number Generation for Cryptographic modules"
+       help
+         This option enables the generic pseudo random number generator
+         for cryptographic modules.  Uses the Algorithm specified in
+         ANSI X9.31 A.2.4
+
 source "drivers/crypto/Kconfig"
 
 endif  # if CRYPTO
index ca024418f4fb6df738f8aab8e71902bebd6bd0a0..ef61b3b646607c6423fb03d1f022ec0e8f471c97 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
 obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
 
 crypto_hash-objs := hash.o
+crypto_hash-objs += ahash.o
 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
 
 obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
@@ -27,6 +28,10 @@ obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
 obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
 obj-$(CONFIG_CRYPTO_MD4) += md4.o
 obj-$(CONFIG_CRYPTO_MD5) += md5.o
+obj-$(CONFIG_CRYPTO_RMD128) += rmd128.o
+obj-$(CONFIG_CRYPTO_RMD160) += rmd160.o
+obj-$(CONFIG_CRYPTO_RMD256) += rmd256.o
+obj-$(CONFIG_CRYPTO_RMD320) += rmd320.o
 obj-$(CONFIG_CRYPTO_SHA1) += sha1_generic.o
 obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o
 obj-$(CONFIG_CRYPTO_SHA512) += sha512_generic.o
@@ -64,7 +69,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o
-
+obj-$(CONFIG_CRYPTO_PRNG) += prng.o
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
 #
diff --git a/crypto/ahash.c b/crypto/ahash.c
new file mode 100644 (file)
index 0000000..27128f2
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Asynchronous Cryptographic Hash operations.
+ *
+ * This is the asynchronous version of hash.c with notification of
+ * completion via a callback.
+ *
+ * Copyright (c) 2008 Loc Ho <lho@amcc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+
+#include "internal.h"
+
+static int hash_walk_next(struct crypto_hash_walk *walk)
+{
+       unsigned int alignmask = walk->alignmask;
+       unsigned int offset = walk->offset;
+       unsigned int nbytes = min(walk->entrylen,
+                                 ((unsigned int)(PAGE_SIZE)) - offset);
+
+       walk->data = crypto_kmap(walk->pg, 0);
+       walk->data += offset;
+
+       if (offset & alignmask)
+               nbytes = alignmask + 1 - (offset & alignmask);
+
+       walk->entrylen -= nbytes;
+       return nbytes;
+}
+
+static int hash_walk_new_entry(struct crypto_hash_walk *walk)
+{
+       struct scatterlist *sg;
+
+       sg = walk->sg;
+       walk->pg = sg_page(sg);
+       walk->offset = sg->offset;
+       walk->entrylen = sg->length;
+
+       if (walk->entrylen > walk->total)
+               walk->entrylen = walk->total;
+       walk->total -= walk->entrylen;
+
+       return hash_walk_next(walk);
+}
+
+int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
+{
+       unsigned int alignmask = walk->alignmask;
+       unsigned int nbytes = walk->entrylen;
+
+       walk->data -= walk->offset;
+
+       if (nbytes && walk->offset & alignmask && !err) {
+               walk->offset += alignmask - 1;
+               walk->offset = ALIGN(walk->offset, alignmask + 1);
+               walk->data += walk->offset;
+
+               nbytes = min(nbytes,
+                            ((unsigned int)(PAGE_SIZE)) - walk->offset);
+               walk->entrylen -= nbytes;
+
+               return nbytes;
+       }
+
+       crypto_kunmap(walk->data, 0);
+       crypto_yield(walk->flags);
+
+       if (err)
+               return err;
+
+       walk->offset = 0;
+
+       if (nbytes)
+               return hash_walk_next(walk);
+
+       if (!walk->total)
+               return 0;
+
+       walk->sg = scatterwalk_sg_next(walk->sg);
+
+       return hash_walk_new_entry(walk);
+}
+EXPORT_SYMBOL_GPL(crypto_hash_walk_done);
+
+int crypto_hash_walk_first(struct ahash_request *req,
+                          struct crypto_hash_walk *walk)
+{
+       walk->total = req->nbytes;
+
+       if (!walk->total)
+               return 0;
+
+       walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
+       walk->sg = req->src;
+       walk->flags = req->base.flags;
+
+       return hash_walk_new_entry(walk);
+}
+EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
+
+static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
+                               unsigned int keylen)
+{
+       struct ahash_alg *ahash = crypto_ahash_alg(tfm);
+       unsigned long alignmask = crypto_ahash_alignmask(tfm);
+       int ret;
+       u8 *buffer, *alignbuffer;
+       unsigned long absize;
+
+       absize = keylen + alignmask;
+       buffer = kmalloc(absize, GFP_ATOMIC);
+       if (!buffer)
+               return -ENOMEM;
+
+       alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+       memcpy(alignbuffer, key, keylen);
+       ret = ahash->setkey(tfm, alignbuffer, keylen);
+       memset(alignbuffer, 0, keylen);
+       kfree(buffer);
+       return ret;
+}
+
+static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+                       unsigned int keylen)
+{
+       struct ahash_alg *ahash = crypto_ahash_alg(tfm);
+       unsigned long alignmask = crypto_ahash_alignmask(tfm);
+
+       if ((unsigned long)key & alignmask)
+               return ahash_setkey_unaligned(tfm, key, keylen);
+
+       return ahash->setkey(tfm, key, keylen);
+}
+
+static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type,
+                                       u32 mask)
+{
+       return alg->cra_ctxsize;
+}
+
+static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+       struct ahash_alg *alg = &tfm->__crt_alg->cra_ahash;
+       struct ahash_tfm *crt   = &tfm->crt_ahash;
+
+       if (alg->digestsize > PAGE_SIZE / 8)
+               return -EINVAL;
+
+       crt->init = alg->init;
+       crt->update = alg->update;
+       crt->final  = alg->final;
+       crt->digest = alg->digest;
+       crt->setkey = ahash_setkey;
+       crt->digestsize = alg->digestsize;
+
+       return 0;
+}
+
+static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
+       __attribute__ ((unused));
+static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
+{
+       seq_printf(m, "type         : ahash\n");
+       seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
+                                            "yes" : "no");
+       seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+       seq_printf(m, "digestsize   : %u\n", alg->cra_hash.digestsize);
+}
+
+const struct crypto_type crypto_ahash_type = {
+       .ctxsize = crypto_ahash_ctxsize,
+       .init = crypto_init_ahash_ops,
+#ifdef CONFIG_PROC_FS
+       .show = crypto_ahash_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_ahash_type);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
index 0a0f41ef255ff4b48e69cebdf26db12157a72c52..d06e33270abea8fae3c5ae97354774bca63bf9b3 100644 (file)
@@ -235,8 +235,12 @@ static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
                return crypto_init_cipher_ops(tfm);
                
        case CRYPTO_ALG_TYPE_DIGEST:
-               return crypto_init_digest_ops(tfm);
-               
+               if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) !=
+                   CRYPTO_ALG_TYPE_HASH_MASK)
+                       return crypto_init_digest_ops_async(tfm);
+               else
+                       return crypto_init_digest_ops(tfm);
+
        case CRYPTO_ALG_TYPE_COMPRESS:
                return crypto_init_compress_ops(tfm);
        
index 493fee7e0a8b46bbd9933d92681e0a7c16d0ab81..b1cc4de6493cfa7604187e4f05429d84f6ad2e58 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
 
 static const u32 camellia_sp1110[256] = {
        0x70707000,0x82828200,0x2c2c2c00,0xececec00,
@@ -335,20 +337,6 @@ static const u32 camellia_sp4404[256] = {
 /*
  *  macros
  */
-#define GETU32(v, pt) \
-    do { \
-       /* latest breed of gcc is clever enough to use move */ \
-       memcpy(&(v), (pt), 4); \
-       (v) = be32_to_cpu(v); \
-    } while(0)
-
-/* rotation right shift 1byte */
-#define ROR8(x) (((x) >> 8) + ((x) << 24))
-/* rotation left shift 1bit */
-#define ROL1(x) (((x) << 1) + ((x) >> 31))
-/* rotation left shift 1byte */
-#define ROL8(x) (((x) << 8) + ((x) >> 24))
-
 #define ROLDQ(ll, lr, rl, rr, w0, w1, bits)            \
     do {                                               \
        w0 = ll;                                        \
@@ -383,7 +371,7 @@ static const u32 camellia_sp4404[256] = {
           ^ camellia_sp3033[(u8)(il >> 8)]                     \
           ^ camellia_sp4404[(u8)(il     )];                    \
        yl ^= yr;                                               \
-       yr = ROR8(yr);                                          \
+       yr = ror32(yr, 8);                                      \
        yr ^= yl;                                               \
     } while(0)
 
@@ -405,7 +393,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[7] ^= subL[1]; subR[7] ^= subR[1];
        subL[1] ^= subR[1] & ~subR[9];
        dw = subL[1] & subL[9],
-               subR[1] ^= ROL1(dw); /* modified for FLinv(kl2) */
+               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl2) */
        /* round 8 */
        subL[11] ^= subL[1]; subR[11] ^= subR[1];
        /* round 10 */
@@ -414,7 +402,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[15] ^= subL[1]; subR[15] ^= subR[1];
        subL[1] ^= subR[1] & ~subR[17];
        dw = subL[1] & subL[17],
-               subR[1] ^= ROL1(dw); /* modified for FLinv(kl4) */
+               subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl4) */
        /* round 14 */
        subL[19] ^= subL[1]; subR[19] ^= subR[1];
        /* round 16 */
@@ -430,7 +418,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        } else {
                subL[1] ^= subR[1] & ~subR[25];
                dw = subL[1] & subL[25],
-                       subR[1] ^= ROL1(dw); /* modified for FLinv(kl6) */
+                       subR[1] ^= rol32(dw, 1); /* modified for FLinv(kl6) */
                /* round 20 */
                subL[27] ^= subL[1]; subR[27] ^= subR[1];
                /* round 22 */
@@ -450,7 +438,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                subL[26] ^= kw4l; subR[26] ^= kw4r;
                kw4l ^= kw4r & ~subR[24];
                dw = kw4l & subL[24],
-                       kw4r ^= ROL1(dw); /* modified for FL(kl5) */
+                       kw4r ^= rol32(dw, 1); /* modified for FL(kl5) */
        }
        /* round 17 */
        subL[22] ^= kw4l; subR[22] ^= kw4r;
@@ -460,7 +448,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[18] ^= kw4l; subR[18] ^= kw4r;
        kw4l ^= kw4r & ~subR[16];
        dw = kw4l & subL[16],
-               kw4r ^= ROL1(dw); /* modified for FL(kl3) */
+               kw4r ^= rol32(dw, 1); /* modified for FL(kl3) */
        /* round 11 */
        subL[14] ^= kw4l; subR[14] ^= kw4r;
        /* round 9 */
@@ -469,7 +457,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        subL[10] ^= kw4l; subR[10] ^= kw4r;
        kw4l ^= kw4r & ~subR[8];
        dw = kw4l & subL[8],
-               kw4r ^= ROL1(dw); /* modified for FL(kl1) */
+               kw4r ^= rol32(dw, 1); /* modified for FL(kl1) */
        /* round 5 */
        subL[6] ^= kw4l; subR[6] ^= kw4r;
        /* round 3 */
@@ -494,7 +482,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(6) = subR[5] ^ subR[7];
        tl = subL[10] ^ (subR[10] & ~subR[8]);
        dw = tl & subL[8],  /* FL(kl1) */
-               tr = subR[10] ^ ROL1(dw);
+               tr = subR[10] ^ rol32(dw, 1);
        SUBKEY_L(7) = subL[6] ^ tl; /* round 6 */
        SUBKEY_R(7) = subR[6] ^ tr;
        SUBKEY_L(8) = subL[8];       /* FL(kl1) */
@@ -503,7 +491,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(9) = subR[9];
        tl = subL[7] ^ (subR[7] & ~subR[9]);
        dw = tl & subL[9],  /* FLinv(kl2) */
-               tr = subR[7] ^ ROL1(dw);
+               tr = subR[7] ^ rol32(dw, 1);
        SUBKEY_L(10) = tl ^ subL[11]; /* round 7 */
        SUBKEY_R(10) = tr ^ subR[11];
        SUBKEY_L(11) = subL[10] ^ subL[12]; /* round 8 */
@@ -516,7 +504,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(14) = subR[13] ^ subR[15];
        tl = subL[18] ^ (subR[18] & ~subR[16]);
        dw = tl & subL[16], /* FL(kl3) */
-               tr = subR[18] ^ ROL1(dw);
+               tr = subR[18] ^ rol32(dw, 1);
        SUBKEY_L(15) = subL[14] ^ tl; /* round 12 */
        SUBKEY_R(15) = subR[14] ^ tr;
        SUBKEY_L(16) = subL[16];     /* FL(kl3) */
@@ -525,7 +513,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        SUBKEY_R(17) = subR[17];
        tl = subL[15] ^ (subR[15] & ~subR[17]);
        dw = tl & subL[17], /* FLinv(kl4) */
-               tr = subR[15] ^ ROL1(dw);
+               tr = subR[15] ^ rol32(dw, 1);
        SUBKEY_L(18) = tl ^ subL[19]; /* round 13 */
        SUBKEY_R(18) = tr ^ subR[19];
        SUBKEY_L(19) = subL[18] ^ subL[20]; /* round 14 */
@@ -544,7 +532,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        } else {
                tl = subL[26] ^ (subR[26] & ~subR[24]);
                dw = tl & subL[24], /* FL(kl5) */
-                       tr = subR[26] ^ ROL1(dw);
+                       tr = subR[26] ^ rol32(dw, 1);
                SUBKEY_L(23) = subL[22] ^ tl; /* round 18 */
                SUBKEY_R(23) = subR[22] ^ tr;
                SUBKEY_L(24) = subL[24];     /* FL(kl5) */
@@ -553,7 +541,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
                SUBKEY_R(25) = subR[25];
                tl = subL[23] ^ (subR[23] & ~subR[25]);
                dw = tl & subL[25], /* FLinv(kl6) */
-                       tr = subR[23] ^ ROL1(dw);
+                       tr = subR[23] ^ rol32(dw, 1);
                SUBKEY_L(26) = tl ^ subL[27]; /* round 19 */
                SUBKEY_R(26) = tr ^ subR[27];
                SUBKEY_L(27) = subL[26] ^ subL[28]; /* round 20 */
@@ -573,17 +561,17 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max)
        /* apply the inverse of the last half of P-function */
        i = 2;
        do {
-               dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = ROL8(dw);/* round 1 */
+               dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */
                SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw;
-               dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = ROL8(dw);/* round 2 */
+               dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */
                SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw;
-               dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = ROL8(dw);/* round 3 */
+               dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */
                SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw;
-               dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = ROL8(dw);/* round 4 */
+               dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */
                SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw;
-               dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = ROL8(dw);/* round 5 */
+               dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 9);/* round 5 */
                SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw;
-               dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = ROL8(dw);/* round 6 */
+               dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */
                SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw;
                i += 8;
        } while (i < max);
@@ -599,10 +587,10 @@ static void camellia_setup128(const unsigned char *key, u32 *subkey)
        /**
         *  k == kll || klr || krl || krr (|| is concatenation)
         */
-       GETU32(kll, key     );
-       GETU32(klr, key +  4);
-       GETU32(krl, key +  8);
-       GETU32(krr, key + 12);
+       kll = get_unaligned_be32(key);
+       klr = get_unaligned_be32(key + 4);
+       krl = get_unaligned_be32(key + 8);
+       krr = get_unaligned_be32(key + 12);
 
        /* generate KL dependent subkeys */
        /* kw1 */
@@ -707,14 +695,14 @@ static void camellia_setup256(const unsigned char *key, u32 *subkey)
         *  key = (kll || klr || krl || krr || krll || krlr || krrl || krrr)
         *  (|| is concatenation)
         */
-       GETU32(kll,  key     );
-       GETU32(klr,  key +  4);
-       GETU32(krl,  key +  8);
-       GETU32(krr,  key + 12);
-       GETU32(krll, key + 16);
-       GETU32(krlr, key + 20);
-       GETU32(krrl, key + 24);
-       GETU32(krrr, key + 28);
+       kll = get_unaligned_be32(key);
+       klr = get_unaligned_be32(key + 4);
+       krl = get_unaligned_be32(key + 8);
+       krr = get_unaligned_be32(key + 12);
+       krll = get_unaligned_be32(key + 16);
+       krlr = get_unaligned_be32(key + 20);
+       krrl = get_unaligned_be32(key + 24);
+       krrr = get_unaligned_be32(key + 28);
 
        /* generate KL dependent subkeys */
        /* kw1 */
@@ -870,13 +858,13 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey)
        t0 &= ll;                                                       \
        t2 |= rr;                                                       \
        rl ^= t2;                                                       \
-       lr ^= ROL1(t0);                                                 \
+       lr ^= rol32(t0, 1);                                             \
        t3 = krl;                                                       \
        t1 = klr;                                                       \
        t3 &= rl;                                                       \
        t1 |= lr;                                                       \
        ll ^= t1;                                                       \
-       rr ^= ROL1(t3);                                                 \
+       rr ^= rol32(t3, 1);                                             \
     } while(0)
 
 #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir)               \
@@ -892,7 +880,7 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey)
        il ^= kl;                                                       \
        ir ^= il ^ kr;                                                  \
        yl ^= ir;                                                       \
-       yr ^= ROR8(il) ^ ir;                                            \
+       yr ^= ror32(il, 8) ^ ir;                                                \
     } while(0)
 
 /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */
index 0dcf64a74e68cf670e361766120e3290c2354ac0..a882d9e4e63e741fd90ec2d6183cee337c841c54 100644 (file)
@@ -5,20 +5,23 @@
  *
  * This module file is a wrapper to invoke the lib/crc32c routines.
  *
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation; either version 2 of the License, or (at your option) 
  * any later version.
  *
  */
+
+#include <crypto/internal/hash.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include <linux/crypto.h>
 #include <linux/crc32c.h>
 #include <linux/kernel.h>
 
-#define CHKSUM_BLOCK_SIZE      32
+#define CHKSUM_BLOCK_SIZE      1
 #define CHKSUM_DIGEST_SIZE     4
 
 struct chksum_ctx {
@@ -71,7 +74,7 @@ static void chksum_final(struct crypto_tfm *tfm, u8 *out)
        *(__le32 *)out = ~cpu_to_le32(mctx->crc);
 }
 
-static int crc32c_cra_init(struct crypto_tfm *tfm)
+static int crc32c_cra_init_old(struct crypto_tfm *tfm)
 {
        struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
 
@@ -79,14 +82,14 @@ static int crc32c_cra_init(struct crypto_tfm *tfm)
        return 0;
 }
 
-static struct crypto_alg alg = {
+static struct crypto_alg old_alg = {
        .cra_name       =       "crc32c",
        .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
        .cra_blocksize  =       CHKSUM_BLOCK_SIZE,
        .cra_ctxsize    =       sizeof(struct chksum_ctx),
        .cra_module     =       THIS_MODULE,
-       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
-       .cra_init       =       crc32c_cra_init,
+       .cra_list       =       LIST_HEAD_INIT(old_alg.cra_list),
+       .cra_init       =       crc32c_cra_init_old,
        .cra_u          =       {
                .digest = {
                         .dia_digestsize=       CHKSUM_DIGEST_SIZE,
@@ -98,14 +101,125 @@ static struct crypto_alg alg = {
        }
 };
 
+/*
+ * Setting the seed allows arbitrary accumulators and flexible XOR policy
+ * If your algorithm starts with ~0, then XOR with ~0 before you set
+ * the seed.
+ */
+static int crc32c_setkey(struct crypto_ahash *hash, const u8 *key,
+                        unsigned int keylen)
+{
+       u32 *mctx = crypto_ahash_ctx(hash);
+
+       if (keylen != sizeof(u32)) {
+               crypto_ahash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+               return -EINVAL;
+       }
+       *mctx = le32_to_cpup((__le32 *)key);
+       return 0;
+}
+
+static int crc32c_init(struct ahash_request *req)
+{
+       u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+       u32 *crcp = ahash_request_ctx(req);
+
+       *crcp = *mctx;
+       return 0;
+}
+
+static int crc32c_update(struct ahash_request *req)
+{
+       struct crypto_hash_walk walk;
+       u32 *crcp = ahash_request_ctx(req);
+       u32 crc = *crcp;
+       int nbytes;
+
+       for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
+            nbytes = crypto_hash_walk_done(&walk, 0))
+               crc = crc32c(crc, walk.data, nbytes);
+
+       *crcp = crc;
+       return 0;
+}
+
+static int crc32c_final(struct ahash_request *req)
+{
+       u32 *crcp = ahash_request_ctx(req);
+       
+       *(__le32 *)req->result = ~cpu_to_le32p(crcp);
+       return 0;
+}
+
+static int crc32c_digest(struct ahash_request *req)
+{
+       struct crypto_hash_walk walk;
+       u32 *mctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+       u32 crc = *mctx;
+       int nbytes;
+
+       for (nbytes = crypto_hash_walk_first(req, &walk); nbytes;
+            nbytes = crypto_hash_walk_done(&walk, 0))
+               crc = crc32c(crc, walk.data, nbytes);
+
+       *(__le32 *)req->result = ~cpu_to_le32(crc);
+       return 0;
+}
+
+static int crc32c_cra_init(struct crypto_tfm *tfm)
+{
+       u32 *key = crypto_tfm_ctx(tfm);
+
+       *key = ~0;
+
+       tfm->crt_ahash.reqsize = sizeof(u32);
+
+       return 0;
+}
+
+static struct crypto_alg alg = {
+       .cra_name               =       "crc32c",
+       .cra_driver_name        =       "crc32c-generic",
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_AHASH,
+       .cra_blocksize          =       CHKSUM_BLOCK_SIZE,
+       .cra_alignmask          =       3,
+       .cra_ctxsize            =       sizeof(u32),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
+       .cra_init               =       crc32c_cra_init,
+       .cra_type               =       &crypto_ahash_type,
+       .cra_u                  =       {
+               .ahash = {
+                        .digestsize    =       CHKSUM_DIGEST_SIZE,
+                        .setkey        =       crc32c_setkey,
+                        .init          =       crc32c_init,
+                        .update        =       crc32c_update,
+                        .final         =       crc32c_final,
+                        .digest        =       crc32c_digest,
+                }
+       }
+};
+
 static int __init crc32c_mod_init(void)
 {
-       return crypto_register_alg(&alg);
+       int err;
+
+       err = crypto_register_alg(&old_alg);
+       if (err)
+               return err;
+
+       err = crypto_register_alg(&alg);
+       if (err)
+               crypto_unregister_alg(&old_alg);
+
+       return err;
 }
 
 static void __exit crc32c_mod_fini(void)
 {
        crypto_unregister_alg(&alg);
+       crypto_unregister_alg(&old_alg);
 }
 
 module_init(crc32c_mod_init);
index b150de562057f59bd85a69f0bb4e3267589c6bff..d29e06b350ffffb55d91fe62a00e7a804a324bbd 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -45,6 +46,13 @@ struct cryptd_blkcipher_request_ctx {
        crypto_completion_t complete;
 };
 
+struct cryptd_hash_ctx {
+       struct crypto_hash *child;
+};
+
+struct cryptd_hash_request_ctx {
+       crypto_completion_t complete;
+};
 
 static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm)
 {
@@ -82,10 +90,8 @@ static void cryptd_blkcipher_crypt(struct ablkcipher_request *req,
 
        rctx = ablkcipher_request_ctx(req);
 
-       if (unlikely(err == -EINPROGRESS)) {
-               rctx->complete(&req->base, err);
-               return;
-       }
+       if (unlikely(err == -EINPROGRESS))
+               goto out;
 
        desc.tfm = child;
        desc.info = req->info;
@@ -95,8 +101,9 @@ static void cryptd_blkcipher_crypt(struct ablkcipher_request *req,
 
        req->base.complete = rctx->complete;
 
+out:
        local_bh_disable();
-       req->base.complete(&req->base, err);
+       rctx->complete(&req->base, err);
        local_bh_enable();
 }
 
@@ -261,6 +268,240 @@ out_put_alg:
        return inst;
 }
 
+static int cryptd_hash_init_tfm(struct crypto_tfm *tfm)
+{
+       struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+       struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
+       struct crypto_spawn *spawn = &ictx->spawn;
+       struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypto_hash *cipher;
+
+       cipher = crypto_spawn_hash(spawn);
+       if (IS_ERR(cipher))
+               return PTR_ERR(cipher);
+
+       ctx->child = cipher;
+       tfm->crt_ahash.reqsize =
+               sizeof(struct cryptd_hash_request_ctx);
+       return 0;
+}
+
+static void cryptd_hash_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct cryptd_state *state = cryptd_get_state(tfm);
+       int active;
+
+       mutex_lock(&state->mutex);
+       active = ahash_tfm_in_queue(&state->queue,
+                               __crypto_ahash_cast(tfm));
+       mutex_unlock(&state->mutex);
+
+       BUG_ON(active);
+
+       crypto_free_hash(ctx->child);
+}
+
+static int cryptd_hash_setkey(struct crypto_ahash *parent,
+                                  const u8 *key, unsigned int keylen)
+{
+       struct cryptd_hash_ctx *ctx   = crypto_ahash_ctx(parent);
+       struct crypto_hash     *child = ctx->child;
+       int err;
+
+       crypto_hash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_hash_set_flags(child, crypto_ahash_get_flags(parent) &
+                                         CRYPTO_TFM_REQ_MASK);
+       err = crypto_hash_setkey(child, key, keylen);
+       crypto_ahash_set_flags(parent, crypto_hash_get_flags(child) &
+                                           CRYPTO_TFM_RES_MASK);
+       return err;
+}
+
+static int cryptd_hash_enqueue(struct ahash_request *req,
+                               crypto_completion_t complete)
+{
+       struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+       struct cryptd_state *state =
+               cryptd_get_state(crypto_ahash_tfm(tfm));
+       int err;
+
+       rctx->complete = req->base.complete;
+       req->base.complete = complete;
+
+       spin_lock_bh(&state->lock);
+       err = ahash_enqueue_request(&state->queue, req);
+       spin_unlock_bh(&state->lock);
+
+       wake_up_process(state->task);
+       return err;
+}
+
+static void cryptd_hash_init(struct crypto_async_request *req_async, int err)
+{
+       struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+       struct crypto_hash     *child = ctx->child;
+       struct ahash_request    *req = ahash_request_cast(req_async);
+       struct cryptd_hash_request_ctx *rctx;
+       struct hash_desc desc;
+
+       rctx = ahash_request_ctx(req);
+
+       if (unlikely(err == -EINPROGRESS))
+               goto out;
+
+       desc.tfm = child;
+       desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_hash_crt(child)->init(&desc);
+
+       req->base.complete = rctx->complete;
+
+out:
+       local_bh_disable();
+       rctx->complete(&req->base, err);
+       local_bh_enable();
+}
+
+static int cryptd_hash_init_enqueue(struct ahash_request *req)
+{
+       return cryptd_hash_enqueue(req, cryptd_hash_init);
+}
+
+static void cryptd_hash_update(struct crypto_async_request *req_async, int err)
+{
+       struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+       struct crypto_hash     *child = ctx->child;
+       struct ahash_request    *req = ahash_request_cast(req_async);
+       struct cryptd_hash_request_ctx *rctx;
+       struct hash_desc desc;
+
+       rctx = ahash_request_ctx(req);
+
+       if (unlikely(err == -EINPROGRESS))
+               goto out;
+
+       desc.tfm = child;
+       desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_hash_crt(child)->update(&desc,
+                                               req->src,
+                                               req->nbytes);
+
+       req->base.complete = rctx->complete;
+
+out:
+       local_bh_disable();
+       rctx->complete(&req->base, err);
+       local_bh_enable();
+}
+
+static int cryptd_hash_update_enqueue(struct ahash_request *req)
+{
+       return cryptd_hash_enqueue(req, cryptd_hash_update);
+}
+
+static void cryptd_hash_final(struct crypto_async_request *req_async, int err)
+{
+       struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+       struct crypto_hash     *child = ctx->child;
+       struct ahash_request    *req = ahash_request_cast(req_async);
+       struct cryptd_hash_request_ctx *rctx;
+       struct hash_desc desc;
+
+       rctx = ahash_request_ctx(req);
+
+       if (unlikely(err == -EINPROGRESS))
+               goto out;
+
+       desc.tfm = child;
+       desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_hash_crt(child)->final(&desc, req->result);
+
+       req->base.complete = rctx->complete;
+
+out:
+       local_bh_disable();
+       rctx->complete(&req->base, err);
+       local_bh_enable();
+}
+
+static int cryptd_hash_final_enqueue(struct ahash_request *req)
+{
+       return cryptd_hash_enqueue(req, cryptd_hash_final);
+}
+
+static void cryptd_hash_digest(struct crypto_async_request *req_async, int err)
+{
+       struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+       struct crypto_hash     *child = ctx->child;
+       struct ahash_request    *req = ahash_request_cast(req_async);
+       struct cryptd_hash_request_ctx *rctx;
+       struct hash_desc desc;
+
+       rctx = ahash_request_ctx(req);
+
+       if (unlikely(err == -EINPROGRESS))
+               goto out;
+
+       desc.tfm = child;
+       desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       err = crypto_hash_crt(child)->digest(&desc,
+                                               req->src,
+                                               req->nbytes,
+                                               req->result);
+
+       req->base.complete = rctx->complete;
+
+out:
+       local_bh_disable();
+       rctx->complete(&req->base, err);
+       local_bh_enable();
+}
+
+static int cryptd_hash_digest_enqueue(struct ahash_request *req)
+{
+       return cryptd_hash_enqueue(req, cryptd_hash_digest);
+}
+
+static struct crypto_instance *cryptd_alloc_hash(
+       struct rtattr **tb, struct cryptd_state *state)
+{
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+
+       alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
+                                 CRYPTO_ALG_TYPE_HASH_MASK);
+       if (IS_ERR(alg))
+               return ERR_PTR(PTR_ERR(alg));
+
+       inst = cryptd_alloc_instance(alg, state);
+       if (IS_ERR(inst))
+               goto out_put_alg;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC;
+       inst->alg.cra_type = &crypto_ahash_type;
+
+       inst->alg.cra_ahash.digestsize = alg->cra_hash.digestsize;
+       inst->alg.cra_ctxsize = sizeof(struct cryptd_hash_ctx);
+
+       inst->alg.cra_init = cryptd_hash_init_tfm;
+       inst->alg.cra_exit = cryptd_hash_exit_tfm;
+
+       inst->alg.cra_ahash.init   = cryptd_hash_init_enqueue;
+       inst->alg.cra_ahash.update = cryptd_hash_update_enqueue;
+       inst->alg.cra_ahash.final  = cryptd_hash_final_enqueue;
+       inst->alg.cra_ahash.setkey = cryptd_hash_setkey;
+       inst->alg.cra_ahash.digest = cryptd_hash_digest_enqueue;
+
+out_put_alg:
+       crypto_mod_put(alg);
+       return inst;
+}
+
 static struct cryptd_state state;
 
 static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
@@ -274,6 +515,8 @@ static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
        switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
        case CRYPTO_ALG_TYPE_BLKCIPHER:
                return cryptd_alloc_blkcipher(tb, &state);
+       case CRYPTO_ALG_TYPE_DIGEST:
+               return cryptd_alloc_hash(tb, &state);
        }
 
        return ERR_PTR(-EINVAL);
index b526cc348b79313e21bea12808976f392b5505a8..ac0919460d143c9e45b10212899d3b2cc3ec3a25 100644 (file)
@@ -12,6 +12,7 @@
  *
  */
 
+#include <crypto/internal/hash.h>
 #include <crypto/scatterwalk.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
@@ -141,7 +142,7 @@ int crypto_init_digest_ops(struct crypto_tfm *tfm)
        struct hash_tfm *ops = &tfm->crt_hash;
        struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
 
-       if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm))
+       if (dalg->dia_digestsize > PAGE_SIZE / 8)
                return -EINVAL;
        
        ops->init       = init;
@@ -157,3 +158,83 @@ int crypto_init_digest_ops(struct crypto_tfm *tfm)
 void crypto_exit_digest_ops(struct crypto_tfm *tfm)
 {
 }
+
+static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key,
+                       unsigned int keylen)
+{
+       crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
+       return -ENOSYS;
+}
+
+static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
+                       unsigned int keylen)
+{
+       struct crypto_tfm    *tfm        = crypto_ahash_tfm(tfm_async);
+       struct digest_alg    *dalg       = &tfm->__crt_alg->cra_digest;
+
+       crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
+       return dalg->dia_setkey(tfm, key, keylen);
+}
+
+static int digest_async_init(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm  = req->base.tfm;
+       struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
+
+       dalg->dia_init(tfm);
+       return 0;
+}
+
+static int digest_async_update(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm = req->base.tfm;
+       struct hash_desc  desc = {
+               .tfm   = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       update(&desc, req->src, req->nbytes);
+       return 0;
+}
+
+static int digest_async_final(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm  = req->base.tfm;
+       struct hash_desc  desc = {
+               .tfm   = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       final(&desc, req->result);
+       return 0;
+}
+
+static int digest_async_digest(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm  = req->base.tfm;
+       struct hash_desc  desc = {
+               .tfm   = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       return digest(&desc, req->src, req->nbytes, req->result);
+}
+
+int crypto_init_digest_ops_async(struct crypto_tfm *tfm)
+{
+       struct ahash_tfm  *crt  = &tfm->crt_ahash;
+       struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
+
+       if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm))
+               return -EINVAL;
+
+       crt->init       = digest_async_init;
+       crt->update     = digest_async_update;
+       crt->final      = digest_async_final;
+       crt->digest     = digest_async_digest;
+       crt->setkey     = dalg->dia_setkey ? digest_async_setkey :
+                                               digest_async_nosetkey;
+       crt->digestsize = dalg->dia_digestsize;
+
+       return 0;
+}
index 7dcff671c19b6d91a6127467b57c4db91a23fff4..cb86b19fd105c320e8b75e1d63d388242b0d716c 100644 (file)
@@ -9,6 +9,7 @@
  * any later version.
  */
 
+#include <crypto/internal/hash.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -59,24 +60,107 @@ static int hash_setkey(struct crypto_hash *crt, const u8 *key,
        return alg->setkey(crt, key, keylen);
 }
 
-static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+static int hash_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
+                       unsigned int keylen)
+{
+       struct crypto_tfm  *tfm      = crypto_ahash_tfm(tfm_async);
+       struct crypto_hash *tfm_hash = __crypto_hash_cast(tfm);
+       struct hash_alg    *alg      = &tfm->__crt_alg->cra_hash;
+
+       return alg->setkey(tfm_hash, key, keylen);
+}
+
+static int hash_async_init(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm = req->base.tfm;
+       struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+       struct hash_desc  desc = {
+               .tfm = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       return alg->init(&desc);
+}
+
+static int hash_async_update(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm = req->base.tfm;
+       struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+       struct hash_desc  desc = {
+               .tfm = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       return alg->update(&desc, req->src, req->nbytes);
+}
+
+static int hash_async_final(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm = req->base.tfm;
+       struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+       struct hash_desc  desc = {
+               .tfm = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       return alg->final(&desc, req->result);
+}
+
+static int hash_async_digest(struct ahash_request *req)
+{
+       struct crypto_tfm *tfm = req->base.tfm;
+       struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+       struct hash_desc  desc = {
+               .tfm = __crypto_hash_cast(tfm),
+               .flags = req->base.flags,
+       };
+
+       return alg->digest(&desc, req->src, req->nbytes, req->result);
+}
+
+static int crypto_init_hash_ops_async(struct crypto_tfm *tfm)
+{
+       struct ahash_tfm *crt = &tfm->crt_ahash;
+       struct hash_alg  *alg = &tfm->__crt_alg->cra_hash;
+
+       crt->init       = hash_async_init;
+       crt->update     = hash_async_update;
+       crt->final      = hash_async_final;
+       crt->digest     = hash_async_digest;
+       crt->setkey     = hash_async_setkey;
+       crt->digestsize = alg->digestsize;
+
+       return 0;
+}
+
+static int crypto_init_hash_ops_sync(struct crypto_tfm *tfm)
 {
        struct hash_tfm *crt = &tfm->crt_hash;
        struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
 
-       if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
-               return -EINVAL;
-
-       crt->init = alg->init;
-       crt->update = alg->update;
-       crt->final = alg->final;
-       crt->digest = alg->digest;
-       crt->setkey = hash_setkey;
+       crt->init       = alg->init;
+       crt->update     = alg->update;
+       crt->final      = alg->final;
+       crt->digest     = alg->digest;
+       crt->setkey     = hash_setkey;
        crt->digestsize = alg->digestsize;
 
        return 0;
 }
 
+static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+       struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+
+       if (alg->digestsize > PAGE_SIZE / 8)
+               return -EINVAL;
+
+       if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) != CRYPTO_ALG_TYPE_HASH_MASK)
+               return crypto_init_hash_ops_async(tfm);
+       else
+               return crypto_init_hash_ops_sync(tfm);
+}
+
 static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
        __attribute__ ((unused));
 static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
index 14c6351e639d9484aa093fac191c7919a99127b4..7ff2d6a8c7d0b5c58b753140cd579e332e385819 100644 (file)
@@ -226,6 +226,7 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb)
        struct crypto_instance *inst;
        struct crypto_alg *alg;
        int err;
+       int ds;
 
        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
        if (err)
@@ -236,6 +237,13 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb)
        if (IS_ERR(alg))
                return ERR_CAST(alg);
 
+       inst = ERR_PTR(-EINVAL);
+       ds = (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+            CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
+                                   alg->cra_digest.dia_digestsize;
+       if (ds > alg->cra_blocksize)
+               goto out_put_alg;
+
        inst = crypto_alloc_instance("hmac", alg);
        if (IS_ERR(inst))
                goto out_put_alg;
@@ -246,14 +254,10 @@ static struct crypto_instance *hmac_alloc(struct rtattr **tb)
        inst->alg.cra_alignmask = alg->cra_alignmask;
        inst->alg.cra_type = &crypto_hash_type;
 
-       inst->alg.cra_hash.digestsize =
-               (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
-               CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
-                                      alg->cra_digest.dia_digestsize;
+       inst->alg.cra_hash.digestsize = ds;
 
        inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
-                               ALIGN(inst->alg.cra_blocksize * 2 +
-                                     inst->alg.cra_hash.digestsize,
+                               ALIGN(inst->alg.cra_blocksize * 2 + ds,
                                      sizeof(void *));
 
        inst->alg.cra_init = hmac_init_tfm;
index 32f4c214560315ccc284346499f6b9428bae1d66..683fcb2d91f41968e946792e82d6eae3e917913c 100644 (file)
@@ -86,6 +86,7 @@ struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask);
 struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
 
 int crypto_init_digest_ops(struct crypto_tfm *tfm);
+int crypto_init_digest_ops_async(struct crypto_tfm *tfm);
 int crypto_init_cipher_ops(struct crypto_tfm *tfm);
 int crypto_init_compress_ops(struct crypto_tfm *tfm);
 
diff --git a/crypto/prng.c b/crypto/prng.c
new file mode 100644 (file)
index 0000000..24e4f32
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * PRNG: Pseudo Random Number Generator
+ *       Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using
+ *       AES 128 cipher in RFC3686 ctr mode
+ *
+ *  (C) Neil Horman <nhorman@tuxdriver.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  any later version.
+ *
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/scatterlist.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/highmem.h>
+#include <linux/moduleparam.h>
+#include <linux/jiffies.h>
+#include <linux/timex.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include "prng.h"
+
+#define TEST_PRNG_ON_START 0
+
+#define DEFAULT_PRNG_KEY "0123456789abcdef1011"
+#define DEFAULT_PRNG_KSZ 20
+#define DEFAULT_PRNG_IV "defaultv"
+#define DEFAULT_PRNG_IVSZ 8
+#define DEFAULT_BLK_SZ 16
+#define DEFAULT_V_SEED "zaybxcwdveuftgsh"
+
+/*
+ * Flags for the prng_context flags field
+ */
+
+#define PRNG_FIXED_SIZE 0x1
+#define PRNG_NEED_RESET 0x2
+
+/*
+ * Note: DT is our counter value
+ *      I is our intermediate value
+ *      V is our seed vector
+ * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
+ * for implementation details
+ */
+
+
+struct prng_context {
+       char *prng_key;
+       char *prng_iv;
+       spinlock_t prng_lock;
+       unsigned char rand_data[DEFAULT_BLK_SZ];
+       unsigned char last_rand_data[DEFAULT_BLK_SZ];
+       unsigned char DT[DEFAULT_BLK_SZ];
+       unsigned char I[DEFAULT_BLK_SZ];
+       unsigned char V[DEFAULT_BLK_SZ];
+       u32 rand_data_valid;
+       struct crypto_blkcipher *tfm;
+       u32 flags;
+};
+
+static int dbg;
+
+static void hexdump(char *note, unsigned char *buf, unsigned int len)
+{
+       if (dbg) {
+               printk(KERN_CRIT "%s", note);
+               print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
+                               16, 1,
+                               buf, len, false);
+       }
+}
+
+#define dbgprint(format, args...) do {if(dbg) printk(format, ##args);} while(0)
+
+static void xor_vectors(unsigned char *in1, unsigned char *in2,
+                       unsigned char *out, unsigned int size)
+{
+       int i;
+
+       for (i=0;i<size;i++)
+               out[i] = in1[i] ^ in2[i];
+
+}
+/*
+ * Returns DEFAULT_BLK_SZ bytes of random data per call
+ * returns 0 if generation succeded, <0 if something went wrong
+ */
+static int _get_more_prng_bytes(struct prng_context *ctx)
+{
+       int i;
+       struct blkcipher_desc desc;
+       struct scatterlist sg_in, sg_out;
+       int ret;
+       unsigned char tmp[DEFAULT_BLK_SZ];
+
+       desc.tfm = ctx->tfm;
+       desc.flags = 0;
+
+
+       dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",ctx);
+
+       hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
+       hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
+       hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
+
+       /*
+        * This algorithm is a 3 stage state machine
+        */
+       for (i=0;i<3;i++) {
+
+               desc.tfm = ctx->tfm;
+               desc.flags = 0;
+               switch (i) {
+                       case 0:
+                               /*
+                                * Start by encrypting the counter value
+                                * This gives us an intermediate value I
+                                */
+                               memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
+                               sg_init_one(&sg_out, &ctx->I[0], DEFAULT_BLK_SZ);
+                               hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
+                               break;
+                       case 1:
+
+                               /*
+                                * Next xor I with our secret vector V
+                                * encrypt that result to obtain our
+                                * pseudo random data which we output
+                                */
+                               xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
+                               sg_init_one(&sg_out, &ctx->rand_data[0], DEFAULT_BLK_SZ);
+                               hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
+                               break;
+                       case 2:
+                               /*
+                                * First check that we didn't produce the same random data
+                                * that we did last time around through this
+                                */
+                               if (!memcmp(ctx->rand_data, ctx->last_rand_data, DEFAULT_BLK_SZ)) {
+                                       printk(KERN_ERR "ctx %p Failed repetition check!\n",
+                                               ctx);
+                                       ctx->flags |= PRNG_NEED_RESET;
+                                       return -1;
+                               }
+                               memcpy(ctx->last_rand_data, ctx->rand_data, DEFAULT_BLK_SZ);
+
+                               /*
+                                * Lastly xor the random data with I
+                                * and encrypt that to obtain a new secret vector V
+                                */
+                               xor_vectors(ctx->rand_data, ctx->I, tmp, DEFAULT_BLK_SZ);
+                               sg_init_one(&sg_out, &ctx->V[0], DEFAULT_BLK_SZ);
+                               hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
+                               break;
+               }
+
+               /* Initialize our input buffer */
+               sg_init_one(&sg_in, &tmp[0], DEFAULT_BLK_SZ);
+
+               /* do the encryption */
+               ret = crypto_blkcipher_encrypt(&desc, &sg_out, &sg_in, DEFAULT_BLK_SZ);
+
+               /* And check the result */
+               if (ret) {
+                       dbgprint(KERN_CRIT "Encryption of new block failed for context %p\n",ctx);
+                       ctx->rand_data_valid = DEFAULT_BLK_SZ;
+                       return -1;
+               }
+
+       }
+
+       /*
+        * Now update our DT value
+        */
+       for (i=DEFAULT_BLK_SZ-1;i>0;i--) {
+               ctx->DT[i] = ctx->DT[i-1];
+       }
+       ctx->DT[0] += 1;
+
+       dbgprint("Returning new block for context %p\n",ctx);
+       ctx->rand_data_valid = 0;
+
+       hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
+       hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
+       hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
+       hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
+
+       return 0;
+}
+
+/* Our exported functions */
+int get_prng_bytes(char *buf, int nbytes, struct prng_context *ctx)
+{
+       unsigned long flags;
+       unsigned char *ptr = buf;
+       unsigned int byte_count = (unsigned int)nbytes;
+       int err;
+
+
+       if (nbytes < 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ctx->prng_lock, flags);
+
+       err = -EFAULT;
+       if (ctx->flags & PRNG_NEED_RESET)
+               goto done;
+
+       /*
+        * If the FIXED_SIZE flag is on, only return whole blocks of
+        * pseudo random data
+        */
+       err = -EINVAL;
+       if (ctx->flags & PRNG_FIXED_SIZE) {
+               if (nbytes < DEFAULT_BLK_SZ)
+                       goto done;
+               byte_count = DEFAULT_BLK_SZ;
+       }
+
+       err = byte_count;
+
+       dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",byte_count, ctx);
+
+
+remainder:
+       if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
+               if (_get_more_prng_bytes(ctx) < 0) {
+                       memset(buf, 0, nbytes);
+                       err = -EFAULT;
+                       goto done;
+               }
+       }
+
+       /*
+        * Copy up to the next whole block size
+        */
+       if (byte_count < DEFAULT_BLK_SZ) {
+               for (;ctx->rand_data_valid < DEFAULT_BLK_SZ; ctx->rand_data_valid++) {
+                       *ptr = ctx->rand_data[ctx->rand_data_valid];
+                       ptr++;
+                       byte_count--;
+                       if (byte_count == 0)
+                               goto done;
+               }
+       }
+
+       /*
+        * Now copy whole blocks
+        */
+       for(;byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
+               if (_get_more_prng_bytes(ctx) < 0) {
+                       memset(buf, 0, nbytes);
+                       err = -1;
+                       goto done;
+               }
+               memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
+               ctx->rand_data_valid += DEFAULT_BLK_SZ;
+               ptr += DEFAULT_BLK_SZ;
+       }
+
+       /*
+        * Now copy any extra partial data
+        */
+       if (byte_count)
+               goto remainder;
+
+done:
+       spin_unlock_irqrestore(&ctx->prng_lock, flags);
+       dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",err, ctx);
+       return err;
+}
+EXPORT_SYMBOL_GPL(get_prng_bytes);
+
+struct prng_context *alloc_prng_context(void)
+{
+       struct prng_context *ctx=kzalloc(sizeof(struct prng_context), GFP_KERNEL);
+
+       spin_lock_init(&ctx->prng_lock);
+
+       if (reset_prng_context(ctx, NULL, NULL, NULL, NULL)) {
+               kfree(ctx);
+               ctx = NULL;
+       }
+
+       dbgprint(KERN_CRIT "returning context %p\n",ctx);
+       return ctx;
+}
+
+EXPORT_SYMBOL_GPL(alloc_prng_context);
+
+void free_prng_context(struct prng_context *ctx)
+{
+       crypto_free_blkcipher(ctx->tfm);
+       kfree(ctx);
+}
+EXPORT_SYMBOL_GPL(free_prng_context);
+
+int reset_prng_context(struct prng_context *ctx,
+                      unsigned char *key, unsigned char *iv,
+                      unsigned char *V, unsigned char *DT)
+{
+       int ret;
+       int iv_len;
+       int rc = -EFAULT;
+
+       spin_lock(&ctx->prng_lock);
+       ctx->flags |= PRNG_NEED_RESET;
+
+       if (key)
+               memcpy(ctx->prng_key,key,strlen(ctx->prng_key));
+       else
+               ctx->prng_key = DEFAULT_PRNG_KEY;
+
+       if (iv)
+               memcpy(ctx->prng_iv,iv, strlen(ctx->prng_iv));
+       else
+               ctx->prng_iv = DEFAULT_PRNG_IV;
+
+       if (V)
+               memcpy(ctx->V,V,DEFAULT_BLK_SZ);
+       else
+               memcpy(ctx->V,DEFAULT_V_SEED,DEFAULT_BLK_SZ);
+
+       if (DT)
+               memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
+       else
+               memset(ctx->DT, 0, DEFAULT_BLK_SZ);
+
+       memset(ctx->rand_data,0,DEFAULT_BLK_SZ);
+       memset(ctx->last_rand_data,0,DEFAULT_BLK_SZ);
+
+       if (ctx->tfm)
+               crypto_free_blkcipher(ctx->tfm);
+
+       ctx->tfm = crypto_alloc_blkcipher("rfc3686(ctr(aes))",0,0);
+       if (!ctx->tfm) {
+               dbgprint(KERN_CRIT "Failed to alloc crypto tfm for context %p\n",ctx->tfm);
+               goto out;
+       }
+
+       ctx->rand_data_valid = DEFAULT_BLK_SZ;
+
+       ret = crypto_blkcipher_setkey(ctx->tfm, ctx->prng_key, strlen(ctx->prng_key));
+       if (ret) {
+               dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
+                       crypto_blkcipher_get_flags(ctx->tfm));
+               crypto_free_blkcipher(ctx->tfm);
+               goto out;
+       }
+
+       iv_len = crypto_blkcipher_ivsize(ctx->tfm);
+       if (iv_len) {
+               crypto_blkcipher_set_iv(ctx->tfm, ctx->prng_iv, iv_len);
+       }
+       rc = 0;
+       ctx->flags &= ~PRNG_NEED_RESET;
+out:
+       spin_unlock(&ctx->prng_lock);
+
+       return rc;
+
+}
+EXPORT_SYMBOL_GPL(reset_prng_context);
+
+/* Module initalization */
+static int __init prng_mod_init(void)
+{
+
+#ifdef TEST_PRNG_ON_START
+       int i;
+       unsigned char tmpbuf[DEFAULT_BLK_SZ];
+
+       struct prng_context *ctx = alloc_prng_context();
+       if (ctx == NULL)
+               return -EFAULT;
+       for (i=0;i<16;i++) {
+               if (get_prng_bytes(tmpbuf, DEFAULT_BLK_SZ, ctx) < 0) {
+                       free_prng_context(ctx);
+                       return -EFAULT;
+               }
+       }
+       free_prng_context(ctx);
+#endif
+
+       return 0;
+}
+
+static void __exit prng_mod_fini(void)
+{
+       return;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Software Pseudo Random Number Generator");
+MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
+module_param(dbg, int, 0);
+MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
+module_init(prng_mod_init);
+module_exit(prng_mod_fini);
diff --git a/crypto/prng.h b/crypto/prng.h
new file mode 100644 (file)
index 0000000..1ac9be5
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * PRNG: Pseudo Random Number Generator
+ *
+ *  (C) Neil Horman <nhorman@tuxdriver.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  any later version.
+ *
+ *
+ */
+
+#ifndef _PRNG_H_
+#define _PRNG_H_
+struct prng_context;
+
+int get_prng_bytes(char *buf, int nbytes, struct prng_context *ctx);
+struct prng_context *alloc_prng_context(void);
+int reset_prng_context(struct prng_context *ctx,
+                       unsigned char *key, unsigned char *iv,
+                       unsigned char *V,
+                       unsigned char *DT);
+void free_prng_context(struct prng_context *ctx);
+
+#endif
+
diff --git a/crypto/ripemd.h b/crypto/ripemd.h
new file mode 100644 (file)
index 0000000..c57a2d4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Common values for RIPEMD algorithms
+ */
+
+#ifndef _CRYPTO_RMD_H
+#define _CRYPTO_RMD_H
+
+#define RMD128_DIGEST_SIZE      16
+#define RMD128_BLOCK_SIZE       64
+
+#define RMD160_DIGEST_SIZE      20
+#define RMD160_BLOCK_SIZE       64
+
+#define RMD256_DIGEST_SIZE      32
+#define RMD256_BLOCK_SIZE       64
+
+#define RMD320_DIGEST_SIZE      40
+#define RMD320_BLOCK_SIZE       64
+
+/* initial values  */
+#define RMD_H0  0x67452301UL
+#define RMD_H1  0xefcdab89UL
+#define RMD_H2  0x98badcfeUL
+#define RMD_H3  0x10325476UL
+#define RMD_H4  0xc3d2e1f0UL
+#define RMD_H5  0x76543210UL
+#define RMD_H6  0xfedcba98UL
+#define RMD_H7  0x89abcdefUL
+#define RMD_H8  0x01234567UL
+#define RMD_H9  0x3c2d1e0fUL
+
+/* constants */
+#define RMD_K1  0x00000000UL
+#define RMD_K2  0x5a827999UL
+#define RMD_K3  0x6ed9eba1UL
+#define RMD_K4  0x8f1bbcdcUL
+#define RMD_K5  0xa953fd4eUL
+#define RMD_K6  0x50a28be6UL
+#define RMD_K7  0x5c4dd124UL
+#define RMD_K8  0x6d703ef3UL
+#define RMD_K9  0x7a6d76e9UL
+
+#endif
diff --git a/crypto/rmd128.c b/crypto/rmd128.c
new file mode 100644 (file)
index 0000000..5de6fa2
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Cryptographic API.
+ *
+ * RIPEMD-128 - RACE Integrity Primitives Evaluation Message Digest.
+ *
+ * Based on the reference implementation by Antoon Bosselaers, ESAT-COSIC
+ *
+ * Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger (at) swiss-it.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/cryptohash.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include "ripemd.h"
+
+struct rmd128_ctx {
+       u64 byte_count;
+       u32 state[4];
+       __le32 buffer[16];
+};
+
+#define K1  RMD_K1
+#define K2  RMD_K2
+#define K3  RMD_K3
+#define K4  RMD_K4
+#define KK1 RMD_K6
+#define KK2 RMD_K7
+#define KK3 RMD_K8
+#define KK4 RMD_K1
+
+#define F1(x, y, z) (x ^ y ^ z)                /* XOR */
+#define F2(x, y, z) (z ^ (x & (y ^ z)))        /* x ? y : z */
+#define F3(x, y, z) ((x | ~y) ^ z)
+#define F4(x, y, z) (y ^ (z & (x ^ y)))        /* z ? x : y */
+
+#define ROUND(a, b, c, d, f, k, x, s)  { \
+       (a) += f((b), (c), (d)) + le32_to_cpup(&(x)) + (k);     \
+       (a) = rol32((a), (s)); \
+}
+
+static void rmd128_transform(u32 *state, const __le32 *in)
+{
+       u32 aa, bb, cc, dd, aaa, bbb, ccc, ddd;
+
+       /* Initialize left lane */
+       aa = state[0];
+       bb = state[1];
+       cc = state[2];
+       dd = state[3];
+
+       /* Initialize right lane */
+       aaa = state[0];
+       bbb = state[1];
+       ccc = state[2];
+       ddd = state[3];
+
+       /* round 1: left lane */
+       ROUND(aa, bb, cc, dd, F1, K1, in[0],  11);
+       ROUND(dd, aa, bb, cc, F1, K1, in[1],  14);
+       ROUND(cc, dd, aa, bb, F1, K1, in[2],  15);
+       ROUND(bb, cc, dd, aa, F1, K1, in[3],  12);
+       ROUND(aa, bb, cc, dd, F1, K1, in[4],   5);
+       ROUND(dd, aa, bb, cc, F1, K1, in[5],   8);
+       ROUND(cc, dd, aa, bb, F1, K1, in[6],   7);
+       ROUND(bb, cc, dd, aa, F1, K1, in[7],   9);
+       ROUND(aa, bb, cc, dd, F1, K1, in[8],  11);
+       ROUND(dd, aa, bb, cc, F1, K1, in[9],  13);
+       ROUND(cc, dd, aa, bb, F1, K1, in[10], 14);
+       ROUND(bb, cc, dd, aa, F1, K1, in[11], 15);
+       ROUND(aa, bb, cc, dd, F1, K1, in[12],  6);
+       ROUND(dd, aa, bb, cc, F1, K1, in[13],  7);
+       ROUND(cc, dd, aa, bb, F1, K1, in[14],  9);
+       ROUND(bb, cc, dd, aa, F1, K1, in[15],  8);
+
+       /* round 2: left lane */
+       ROUND(aa, bb, cc, dd, F2, K2, in[7],   7);
+       ROUND(dd, aa, bb, cc, F2, K2, in[4],   6);
+       ROUND(cc, dd, aa, bb, F2, K2, in[13],  8);
+       ROUND(bb, cc, dd, aa, F2, K2, in[1],  13);
+       ROUND(aa, bb, cc, dd, F2, K2, in[10], 11);
+       ROUND(dd, aa, bb, cc, F2, K2, in[6],   9);
+       ROUND(cc, dd, aa, bb, F2, K2, in[15],  7);
+       ROUND(bb, cc, dd, aa, F2, K2, in[3],  15);
+       ROUND(aa, bb, cc, dd, F2, K2, in[12],  7);
+       ROUND(dd, aa, bb, cc, F2, K2, in[0],  12);
+       ROUND(cc, dd, aa, bb, F2, K2, in[9],  15);
+       ROUND(bb, cc, dd, aa, F2, K2, in[5],   9);
+       ROUND(aa, bb, cc, dd, F2, K2, in[2],  11);
+       ROUND(dd, aa, bb, cc, F2, K2, in[14],  7);
+       ROUND(cc, dd, aa, bb, F2, K2, in[11], 13);
+       ROUND(bb, cc, dd, aa, F2, K2, in[8],  12);
+
+       /* round 3: left lane */
+       ROUND(aa, bb, cc, dd, F3, K3, in[3],  11);
+       ROUND(dd, aa, bb, cc, F3, K3, in[10], 13);
+       ROUND(cc, dd, aa, bb, F3, K3, in[14],  6);
+       ROUND(bb, cc, dd, aa, F3, K3, in[4],   7);
+       ROUND(aa, bb, cc, dd, F3, K3, in[9],  14);
+       ROUND(dd, aa, bb, cc, F3, K3, in[15],  9);
+       ROUND(cc, dd, aa, bb, F3, K3, in[8],  13);
+       ROUND(bb, cc, dd, aa, F3, K3, in[1],  15);
+       ROUND(aa, bb, cc, dd, F3, K3, in[2],  14);
+       ROUND(dd, aa, bb, cc, F3, K3, in[7],   8);
+       ROUND(cc, dd, aa, bb, F3, K3, in[0],  13);
+       ROUND(bb, cc, dd, aa, F3, K3, in[6],   6);
+       ROUND(aa, bb, cc, dd, F3, K3, in[13],  5);
+       ROUND(dd, aa, bb, cc, F3, K3, in[11], 12);
+       ROUND(cc, dd, aa, bb, F3, K3, in[5],   7);
+       ROUND(bb, cc, dd, aa, F3, K3, in[12],  5);
+
+       /* round 4: left lane */
+       ROUND(aa, bb, cc, dd, F4, K4, in[1],  11);
+       ROUND(dd, aa, bb, cc, F4, K4, in[9],  12);
+       ROUND(cc, dd, aa, bb, F4, K4, in[11], 14);
+       ROUND(bb, cc, dd, aa, F4, K4, in[10], 15);
+       ROUND(aa, bb, cc, dd, F4, K4, in[0],  14);
+       ROUND(dd, aa, bb, cc, F4, K4, in[8],  15);
+       ROUND(cc, dd, aa, bb, F4, K4, in[12],  9);
+       ROUND(bb, cc, dd, aa, F4, K4, in[4],   8);
+       ROUND(aa, bb, cc, dd, F4, K4, in[13],  9);
+       ROUND(dd, aa, bb, cc, F4, K4, in[3],  14);
+       ROUND(cc, dd, aa, bb, F4, K4, in[7],   5);
+       ROUND(bb, cc, dd, aa, F4, K4, in[15],  6);
+       ROUND(aa, bb, cc, dd, F4, K4, in[14],  8);
+       ROUND(dd, aa, bb, cc, F4, K4, in[5],   6);
+       ROUND(cc, dd, aa, bb, F4, K4, in[6],   5);
+       ROUND(bb, cc, dd, aa, F4, K4, in[2],  12);
+
+       /* round 1: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[5],   8);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[14],  9);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[7],   9);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[0],  11);
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[9],  13);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[2],  15);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[11], 15);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[4],   5);
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[13],  7);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[6],   7);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[15],  8);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[8],  11);
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[1],  14);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[10], 14);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[3],  12);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[12],  6);
+
+       /* round 2: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[6],   9);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[11], 13);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[3],  15);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[7],   7);
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[0],  12);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[13],  8);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[5],   9);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[10], 11);
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[14],  7);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[15],  7);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[8],  12);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[12],  7);
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[4],   6);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[9],  15);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[1],  13);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[2],  11);
+
+       /* round 3: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[15],  9);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[5],   7);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[1],  15);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[3],  11);
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[7],   8);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[14],  6);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[6],   6);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[9],  14);
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[11], 12);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[8],  13);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[12],  5);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[2],  14);
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[10], 13);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[0],  13);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[4],   7);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[13],  5);
+
+       /* round 4: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[8],  15);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[6],   5);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[4],   8);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[1],  11);
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[3],  14);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[11], 14);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[15],  6);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[0],  14);
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[5],   6);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[12],  9);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[2],  12);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[13],  9);
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[9],  12);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[7],   5);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[10], 15);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[14],  8);
+
+       /* combine results */
+       ddd += cc + state[1];           /* final result for state[0] */
+       state[1] = state[2] + dd + aaa;
+       state[2] = state[3] + aa + bbb;
+       state[3] = state[0] + bb + ccc;
+       state[0] = ddd;
+
+       return;
+}
+
+static void rmd128_init(struct crypto_tfm *tfm)
+{
+       struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm);
+
+       rctx->byte_count = 0;
+
+       rctx->state[0] = RMD_H0;
+       rctx->state[1] = RMD_H1;
+       rctx->state[2] = RMD_H2;
+       rctx->state[3] = RMD_H3;
+
+       memset(rctx->buffer, 0, sizeof(rctx->buffer));
+}
+
+static void rmd128_update(struct crypto_tfm *tfm, const u8 *data,
+                         unsigned int len)
+{
+       struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm);
+       const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
+
+       rctx->byte_count += len;
+
+       /* Enough space in buffer? If so copy and we're done */
+       if (avail > len) {
+               memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+                      data, len);
+               return;
+       }
+
+       memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+              data, avail);
+
+       rmd128_transform(rctx->state, rctx->buffer);
+       data += avail;
+       len -= avail;
+
+       while (len >= sizeof(rctx->buffer)) {
+               memcpy(rctx->buffer, data, sizeof(rctx->buffer));
+               rmd128_transform(rctx->state, rctx->buffer);
+               data += sizeof(rctx->buffer);
+               len -= sizeof(rctx->buffer);
+       }
+
+       memcpy(rctx->buffer, data, len);
+}
+
+/* Add padding and return the message digest. */
+static void rmd128_final(struct crypto_tfm *tfm, u8 *out)
+{
+       struct rmd128_ctx *rctx = crypto_tfm_ctx(tfm);
+       u32 i, index, padlen;
+       __le64 bits;
+       __le32 *dst = (__le32 *)out;
+       static const u8 padding[64] = { 0x80, };
+
+       bits = cpu_to_le64(rctx->byte_count << 3);
+
+       /* Pad out to 56 mod 64 */
+       index = rctx->byte_count & 0x3f;
+       padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+       rmd128_update(tfm, padding, padlen);
+
+       /* Append length */
+       rmd128_update(tfm, (const u8 *)&bits, sizeof(bits));
+
+       /* Store state in digest */
+       for (i = 0; i < 4; i++)
+               dst[i] = cpu_to_le32p(&rctx->state[i]);
+
+       /* Wipe context */
+       memset(rctx, 0, sizeof(*rctx));
+}
+
+static struct crypto_alg alg = {
+       .cra_name        =      "rmd128",
+       .cra_driver_name =      "rmd128",
+       .cra_flags       =      CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize   =      RMD128_BLOCK_SIZE,
+       .cra_ctxsize     =      sizeof(struct rmd128_ctx),
+       .cra_module      =      THIS_MODULE,
+       .cra_list        =      LIST_HEAD_INIT(alg.cra_list),
+       .cra_u           =      { .digest = {
+       .dia_digestsize  =      RMD128_DIGEST_SIZE,
+       .dia_init        =      rmd128_init,
+       .dia_update      =      rmd128_update,
+       .dia_final       =      rmd128_final } }
+};
+
+static int __init rmd128_mod_init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit rmd128_mod_fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(rmd128_mod_init);
+module_exit(rmd128_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RIPEMD-128 Message Digest");
+
+MODULE_ALIAS("rmd128");
diff --git a/crypto/rmd160.c b/crypto/rmd160.c
new file mode 100644 (file)
index 0000000..f001ec7
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Cryptographic API.
+ *
+ * RIPEMD-160 - RACE Integrity Primitives Evaluation Message Digest.
+ *
+ * Based on the reference implementation by Antoon Bosselaers, ESAT-COSIC
+ *
+ * Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger (at) swiss-it.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/cryptohash.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include "ripemd.h"
+
+struct rmd160_ctx {
+       u64 byte_count;
+       u32 state[5];
+       __le32 buffer[16];
+};
+
+#define K1  RMD_K1
+#define K2  RMD_K2
+#define K3  RMD_K3
+#define K4  RMD_K4
+#define K5  RMD_K5
+#define KK1 RMD_K6
+#define KK2 RMD_K7
+#define KK3 RMD_K8
+#define KK4 RMD_K9
+#define KK5 RMD_K1
+
+#define F1(x, y, z) (x ^ y ^ z)                /* XOR */
+#define F2(x, y, z) (z ^ (x & (y ^ z)))        /* x ? y : z */
+#define F3(x, y, z) ((x | ~y) ^ z)
+#define F4(x, y, z) (y ^ (z & (x ^ y)))        /* z ? x : y */
+#define F5(x, y, z) (x ^ (y | ~z))
+
+#define ROUND(a, b, c, d, e, f, k, x, s)  { \
+       (a) += f((b), (c), (d)) + le32_to_cpup(&(x)) + (k); \
+       (a) = rol32((a), (s)) + (e); \
+       (c) = rol32((c), 10); \
+}
+
+static void rmd160_transform(u32 *state, const __le32 *in)
+{
+       u32 aa, bb, cc, dd, ee, aaa, bbb, ccc, ddd, eee;
+
+       /* Initialize left lane */
+       aa = state[0];
+       bb = state[1];
+       cc = state[2];
+       dd = state[3];
+       ee = state[4];
+
+       /* Initialize right lane */
+       aaa = state[0];
+       bbb = state[1];
+       ccc = state[2];
+       ddd = state[3];
+       eee = state[4];
+
+       /* round 1: left lane */
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[0],  11);
+       ROUND(ee, aa, bb, cc, dd, F1, K1, in[1],  14);
+       ROUND(dd, ee, aa, bb, cc, F1, K1, in[2],  15);
+       ROUND(cc, dd, ee, aa, bb, F1, K1, in[3],  12);
+       ROUND(bb, cc, dd, ee, aa, F1, K1, in[4],   5);
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[5],   8);
+       ROUND(ee, aa, bb, cc, dd, F1, K1, in[6],   7);
+       ROUND(dd, ee, aa, bb, cc, F1, K1, in[7],   9);
+       ROUND(cc, dd, ee, aa, bb, F1, K1, in[8],  11);
+       ROUND(bb, cc, dd, ee, aa, F1, K1, in[9],  13);
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[10], 14);
+       ROUND(ee, aa, bb, cc, dd, F1, K1, in[11], 15);
+       ROUND(dd, ee, aa, bb, cc, F1, K1, in[12],  6);
+       ROUND(cc, dd, ee, aa, bb, F1, K1, in[13],  7);
+       ROUND(bb, cc, dd, ee, aa, F1, K1, in[14],  9);
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[15],  8);
+
+       /* round 2: left lane" */
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[7],   7);
+       ROUND(dd, ee, aa, bb, cc, F2, K2, in[4],   6);
+       ROUND(cc, dd, ee, aa, bb, F2, K2, in[13],  8);
+       ROUND(bb, cc, dd, ee, aa, F2, K2, in[1],  13);
+       ROUND(aa, bb, cc, dd, ee, F2, K2, in[10], 11);
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[6],   9);
+       ROUND(dd, ee, aa, bb, cc, F2, K2, in[15],  7);
+       ROUND(cc, dd, ee, aa, bb, F2, K2, in[3],  15);
+       ROUND(bb, cc, dd, ee, aa, F2, K2, in[12],  7);
+       ROUND(aa, bb, cc, dd, ee, F2, K2, in[0],  12);
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[9],  15);
+       ROUND(dd, ee, aa, bb, cc, F2, K2, in[5],   9);
+       ROUND(cc, dd, ee, aa, bb, F2, K2, in[2],  11);
+       ROUND(bb, cc, dd, ee, aa, F2, K2, in[14],  7);
+       ROUND(aa, bb, cc, dd, ee, F2, K2, in[11], 13);
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[8],  12);
+
+       /* round 3: left lane" */
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[3],  11);
+       ROUND(cc, dd, ee, aa, bb, F3, K3, in[10], 13);
+       ROUND(bb, cc, dd, ee, aa, F3, K3, in[14],  6);
+       ROUND(aa, bb, cc, dd, ee, F3, K3, in[4],   7);
+       ROUND(ee, aa, bb, cc, dd, F3, K3, in[9],  14);
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[15],  9);
+       ROUND(cc, dd, ee, aa, bb, F3, K3, in[8],  13);
+       ROUND(bb, cc, dd, ee, aa, F3, K3, in[1],  15);
+       ROUND(aa, bb, cc, dd, ee, F3, K3, in[2],  14);
+       ROUND(ee, aa, bb, cc, dd, F3, K3, in[7],   8);
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[0],  13);
+       ROUND(cc, dd, ee, aa, bb, F3, K3, in[6],   6);
+       ROUND(bb, cc, dd, ee, aa, F3, K3, in[13],  5);
+       ROUND(aa, bb, cc, dd, ee, F3, K3, in[11], 12);
+       ROUND(ee, aa, bb, cc, dd, F3, K3, in[5],   7);
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[12],  5);
+
+       /* round 4: left lane" */
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[1],  11);
+       ROUND(bb, cc, dd, ee, aa, F4, K4, in[9],  12);
+       ROUND(aa, bb, cc, dd, ee, F4, K4, in[11], 14);
+       ROUND(ee, aa, bb, cc, dd, F4, K4, in[10], 15);
+       ROUND(dd, ee, aa, bb, cc, F4, K4, in[0],  14);
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[8],  15);
+       ROUND(bb, cc, dd, ee, aa, F4, K4, in[12],  9);
+       ROUND(aa, bb, cc, dd, ee, F4, K4, in[4],   8);
+       ROUND(ee, aa, bb, cc, dd, F4, K4, in[13],  9);
+       ROUND(dd, ee, aa, bb, cc, F4, K4, in[3],  14);
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[7],   5);
+       ROUND(bb, cc, dd, ee, aa, F4, K4, in[15],  6);
+       ROUND(aa, bb, cc, dd, ee, F4, K4, in[14],  8);
+       ROUND(ee, aa, bb, cc, dd, F4, K4, in[5],   6);
+       ROUND(dd, ee, aa, bb, cc, F4, K4, in[6],   5);
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[2],  12);
+
+       /* round 5: left lane" */
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[4],   9);
+       ROUND(aa, bb, cc, dd, ee, F5, K5, in[0],  15);
+       ROUND(ee, aa, bb, cc, dd, F5, K5, in[5],   5);
+       ROUND(dd, ee, aa, bb, cc, F5, K5, in[9],  11);
+       ROUND(cc, dd, ee, aa, bb, F5, K5, in[7],   6);
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[12],  8);
+       ROUND(aa, bb, cc, dd, ee, F5, K5, in[2],  13);
+       ROUND(ee, aa, bb, cc, dd, F5, K5, in[10], 12);
+       ROUND(dd, ee, aa, bb, cc, F5, K5, in[14],  5);
+       ROUND(cc, dd, ee, aa, bb, F5, K5, in[1],  12);
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[3],  13);
+       ROUND(aa, bb, cc, dd, ee, F5, K5, in[8],  14);
+       ROUND(ee, aa, bb, cc, dd, F5, K5, in[11], 11);
+       ROUND(dd, ee, aa, bb, cc, F5, K5, in[6],   8);
+       ROUND(cc, dd, ee, aa, bb, F5, K5, in[15],  5);
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[13],  6);
+
+       /* round 1: right lane */
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[5],   8);
+       ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[14],  9);
+       ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[7],   9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[0],  11);
+       ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[9],  13);
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[2],  15);
+       ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[11], 15);
+       ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[4],   5);
+       ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[13],  7);
+       ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[6],   7);
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[15],  8);
+       ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[8],  11);
+       ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[1],  14);
+       ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[10], 14);
+       ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[3],  12);
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[12],  6);
+
+       /* round 2: right lane */
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[6],   9);
+       ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[11], 13);
+       ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[3],  15);
+       ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[7],   7);
+       ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[0],  12);
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[13],  8);
+       ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[5],   9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[10], 11);
+       ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[14],  7);
+       ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[15],  7);
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[8],  12);
+       ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[12],  7);
+       ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[4],   6);
+       ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[9],  15);
+       ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[1],  13);
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[2],  11);
+
+       /* round 3: right lane */
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[15],  9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[5],   7);
+       ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[1],  15);
+       ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[3],  11);
+       ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[7],   8);
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[14],  6);
+       ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[6],   6);
+       ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[9],  14);
+       ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[11], 12);
+       ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[8],  13);
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[12],  5);
+       ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[2],  14);
+       ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[10], 13);
+       ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[0],  13);
+       ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[4],   7);
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[13],  5);
+
+       /* round 4: right lane */
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[8],  15);
+       ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[6],   5);
+       ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[4],   8);
+       ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[1],  11);
+       ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[3],  14);
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[11], 14);
+       ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[15],  6);
+       ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[0],  14);
+       ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[5],   6);
+       ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[12],  9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[2],  12);
+       ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[13],  9);
+       ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[9],  12);
+       ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[7],   5);
+       ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[10], 15);
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[14],  8);
+
+       /* round 5: right lane */
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[12],  8);
+       ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[15],  5);
+       ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[10], 12);
+       ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[4],   9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[1],  12);
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[5],   5);
+       ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[8],  14);
+       ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[7],   6);
+       ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[6],   8);
+       ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[2],  13);
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[13],  6);
+       ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[14],  5);
+       ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[0],  15);
+       ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[3],  13);
+       ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[9],  11);
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[11], 11);
+
+       /* combine results */
+       ddd += cc + state[1];           /* final result for state[0] */
+       state[1] = state[2] + dd + eee;
+       state[2] = state[3] + ee + aaa;
+       state[3] = state[4] + aa + bbb;
+       state[4] = state[0] + bb + ccc;
+       state[0] = ddd;
+
+       return;
+}
+
+static void rmd160_init(struct crypto_tfm *tfm)
+{
+       struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm);
+
+       rctx->byte_count = 0;
+
+       rctx->state[0] = RMD_H0;
+       rctx->state[1] = RMD_H1;
+       rctx->state[2] = RMD_H2;
+       rctx->state[3] = RMD_H3;
+       rctx->state[4] = RMD_H4;
+
+       memset(rctx->buffer, 0, sizeof(rctx->buffer));
+}
+
+static void rmd160_update(struct crypto_tfm *tfm, const u8 *data,
+                         unsigned int len)
+{
+       struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm);
+       const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
+
+       rctx->byte_count += len;
+
+       /* Enough space in buffer? If so copy and we're done */
+       if (avail > len) {
+               memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+                      data, len);
+               return;
+       }
+
+       memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+              data, avail);
+
+       rmd160_transform(rctx->state, rctx->buffer);
+       data += avail;
+       len -= avail;
+
+       while (len >= sizeof(rctx->buffer)) {
+               memcpy(rctx->buffer, data, sizeof(rctx->buffer));
+               rmd160_transform(rctx->state, rctx->buffer);
+               data += sizeof(rctx->buffer);
+               len -= sizeof(rctx->buffer);
+       }
+
+       memcpy(rctx->buffer, data, len);
+}
+
+/* Add padding and return the message digest. */
+static void rmd160_final(struct crypto_tfm *tfm, u8 *out)
+{
+       struct rmd160_ctx *rctx = crypto_tfm_ctx(tfm);
+       u32 i, index, padlen;
+       __le64 bits;
+       __le32 *dst = (__le32 *)out;
+       static const u8 padding[64] = { 0x80, };
+
+       bits = cpu_to_le64(rctx->byte_count << 3);
+
+       /* Pad out to 56 mod 64 */
+       index = rctx->byte_count & 0x3f;
+       padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+       rmd160_update(tfm, padding, padlen);
+
+       /* Append length */
+       rmd160_update(tfm, (const u8 *)&bits, sizeof(bits));
+
+       /* Store state in digest */
+       for (i = 0; i < 5; i++)
+               dst[i] = cpu_to_le32p(&rctx->state[i]);
+
+       /* Wipe context */
+       memset(rctx, 0, sizeof(*rctx));
+}
+
+static struct crypto_alg alg = {
+       .cra_name        =      "rmd160",
+       .cra_driver_name =      "rmd160",
+       .cra_flags       =      CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize   =      RMD160_BLOCK_SIZE,
+       .cra_ctxsize     =      sizeof(struct rmd160_ctx),
+       .cra_module      =      THIS_MODULE,
+       .cra_list        =      LIST_HEAD_INIT(alg.cra_list),
+       .cra_u           =      { .digest = {
+       .dia_digestsize  =      RMD160_DIGEST_SIZE,
+       .dia_init        =      rmd160_init,
+       .dia_update      =      rmd160_update,
+       .dia_final       =      rmd160_final } }
+};
+
+static int __init rmd160_mod_init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit rmd160_mod_fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(rmd160_mod_init);
+module_exit(rmd160_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RIPEMD-160 Message Digest");
+
+MODULE_ALIAS("rmd160");
diff --git a/crypto/rmd256.c b/crypto/rmd256.c
new file mode 100644 (file)
index 0000000..e3de5b4
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Cryptographic API.
+ *
+ * RIPEMD-256 - RACE Integrity Primitives Evaluation Message Digest.
+ *
+ * Based on the reference implementation by Antoon Bosselaers, ESAT-COSIC
+ *
+ * Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger (at) swiss-it.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/cryptohash.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include "ripemd.h"
+
+struct rmd256_ctx {
+       u64 byte_count;
+       u32 state[8];
+       __le32 buffer[16];
+};
+
+#define K1  RMD_K1
+#define K2  RMD_K2
+#define K3  RMD_K3
+#define K4  RMD_K4
+#define KK1 RMD_K6
+#define KK2 RMD_K7
+#define KK3 RMD_K8
+#define KK4 RMD_K1
+
+#define F1(x, y, z) (x ^ y ^ z)                /* XOR */
+#define F2(x, y, z) (z ^ (x & (y ^ z)))        /* x ? y : z */
+#define F3(x, y, z) ((x | ~y) ^ z)
+#define F4(x, y, z) (y ^ (z & (x ^ y)))        /* z ? x : y */
+
+#define ROUND(a, b, c, d, f, k, x, s)  { \
+       (a) += f((b), (c), (d)) + le32_to_cpup(&(x)) + (k); \
+       (a) = rol32((a), (s)); \
+}
+
+static void rmd256_transform(u32 *state, const __le32 *in)
+{
+       u32 aa, bb, cc, dd, aaa, bbb, ccc, ddd, tmp;
+
+       /* Initialize left lane */
+       aa = state[0];
+       bb = state[1];
+       cc = state[2];
+       dd = state[3];
+
+       /* Initialize right lane */
+       aaa = state[4];
+       bbb = state[5];
+       ccc = state[6];
+       ddd = state[7];
+
+       /* round 1: left lane */
+       ROUND(aa, bb, cc, dd, F1, K1, in[0],  11);
+       ROUND(dd, aa, bb, cc, F1, K1, in[1],  14);
+       ROUND(cc, dd, aa, bb, F1, K1, in[2],  15);
+       ROUND(bb, cc, dd, aa, F1, K1, in[3],  12);
+       ROUND(aa, bb, cc, dd, F1, K1, in[4],   5);
+       ROUND(dd, aa, bb, cc, F1, K1, in[5],   8);
+       ROUND(cc, dd, aa, bb, F1, K1, in[6],   7);
+       ROUND(bb, cc, dd, aa, F1, K1, in[7],   9);
+       ROUND(aa, bb, cc, dd, F1, K1, in[8],  11);
+       ROUND(dd, aa, bb, cc, F1, K1, in[9],  13);
+       ROUND(cc, dd, aa, bb, F1, K1, in[10], 14);
+       ROUND(bb, cc, dd, aa, F1, K1, in[11], 15);
+       ROUND(aa, bb, cc, dd, F1, K1, in[12],  6);
+       ROUND(dd, aa, bb, cc, F1, K1, in[13],  7);
+       ROUND(cc, dd, aa, bb, F1, K1, in[14],  9);
+       ROUND(bb, cc, dd, aa, F1, K1, in[15],  8);
+
+       /* round 1: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[5],   8);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[14],  9);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[7],   9);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[0],  11);
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[9],  13);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[2],  15);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[11], 15);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[4],   5);
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[13],  7);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[6],   7);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[15],  8);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[8],  11);
+       ROUND(aaa, bbb, ccc, ddd, F4, KK1, in[1],  14);
+       ROUND(ddd, aaa, bbb, ccc, F4, KK1, in[10], 14);
+       ROUND(ccc, ddd, aaa, bbb, F4, KK1, in[3],  12);
+       ROUND(bbb, ccc, ddd, aaa, F4, KK1, in[12],  6);
+
+       /* Swap contents of "a" registers */
+       tmp = aa; aa = aaa; aaa = tmp;
+
+       /* round 2: left lane */
+       ROUND(aa, bb, cc, dd, F2, K2, in[7],   7);
+       ROUND(dd, aa, bb, cc, F2, K2, in[4],   6);
+       ROUND(cc, dd, aa, bb, F2, K2, in[13],  8);
+       ROUND(bb, cc, dd, aa, F2, K2, in[1],  13);
+       ROUND(aa, bb, cc, dd, F2, K2, in[10], 11);
+       ROUND(dd, aa, bb, cc, F2, K2, in[6],   9);
+       ROUND(cc, dd, aa, bb, F2, K2, in[15],  7);
+       ROUND(bb, cc, dd, aa, F2, K2, in[3],  15);
+       ROUND(aa, bb, cc, dd, F2, K2, in[12],  7);
+       ROUND(dd, aa, bb, cc, F2, K2, in[0],  12);
+       ROUND(cc, dd, aa, bb, F2, K2, in[9],  15);
+       ROUND(bb, cc, dd, aa, F2, K2, in[5],   9);
+       ROUND(aa, bb, cc, dd, F2, K2, in[2],  11);
+       ROUND(dd, aa, bb, cc, F2, K2, in[14],  7);
+       ROUND(cc, dd, aa, bb, F2, K2, in[11], 13);
+       ROUND(bb, cc, dd, aa, F2, K2, in[8],  12);
+
+       /* round 2: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[6],   9);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[11], 13);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[3],  15);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[7],   7);
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[0],  12);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[13],  8);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[5],   9);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[10], 11);
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[14],  7);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[15],  7);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[8],  12);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[12],  7);
+       ROUND(aaa, bbb, ccc, ddd, F3, KK2, in[4],   6);
+       ROUND(ddd, aaa, bbb, ccc, F3, KK2, in[9],  15);
+       ROUND(ccc, ddd, aaa, bbb, F3, KK2, in[1],  13);
+       ROUND(bbb, ccc, ddd, aaa, F3, KK2, in[2],  11);
+
+       /* Swap contents of "b" registers */
+       tmp = bb; bb = bbb; bbb = tmp;
+
+       /* round 3: left lane */
+       ROUND(aa, bb, cc, dd, F3, K3, in[3],  11);
+       ROUND(dd, aa, bb, cc, F3, K3, in[10], 13);
+       ROUND(cc, dd, aa, bb, F3, K3, in[14],  6);
+       ROUND(bb, cc, dd, aa, F3, K3, in[4],   7);
+       ROUND(aa, bb, cc, dd, F3, K3, in[9],  14);
+       ROUND(dd, aa, bb, cc, F3, K3, in[15],  9);
+       ROUND(cc, dd, aa, bb, F3, K3, in[8],  13);
+       ROUND(bb, cc, dd, aa, F3, K3, in[1],  15);
+       ROUND(aa, bb, cc, dd, F3, K3, in[2],  14);
+       ROUND(dd, aa, bb, cc, F3, K3, in[7],   8);
+       ROUND(cc, dd, aa, bb, F3, K3, in[0],  13);
+       ROUND(bb, cc, dd, aa, F3, K3, in[6],   6);
+       ROUND(aa, bb, cc, dd, F3, K3, in[13],  5);
+       ROUND(dd, aa, bb, cc, F3, K3, in[11], 12);
+       ROUND(cc, dd, aa, bb, F3, K3, in[5],   7);
+       ROUND(bb, cc, dd, aa, F3, K3, in[12],  5);
+
+       /* round 3: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[15],  9);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[5],   7);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[1],  15);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[3],  11);
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[7],   8);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[14],  6);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[6],   6);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[9],  14);
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[11], 12);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[8],  13);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[12],  5);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[2],  14);
+       ROUND(aaa, bbb, ccc, ddd, F2, KK3, in[10], 13);
+       ROUND(ddd, aaa, bbb, ccc, F2, KK3, in[0],  13);
+       ROUND(ccc, ddd, aaa, bbb, F2, KK3, in[4],   7);
+       ROUND(bbb, ccc, ddd, aaa, F2, KK3, in[13],  5);
+
+       /* Swap contents of "c" registers */
+       tmp = cc; cc = ccc; ccc = tmp;
+
+       /* round 4: left lane */
+       ROUND(aa, bb, cc, dd, F4, K4, in[1],  11);
+       ROUND(dd, aa, bb, cc, F4, K4, in[9],  12);
+       ROUND(cc, dd, aa, bb, F4, K4, in[11], 14);
+       ROUND(bb, cc, dd, aa, F4, K4, in[10], 15);
+       ROUND(aa, bb, cc, dd, F4, K4, in[0],  14);
+       ROUND(dd, aa, bb, cc, F4, K4, in[8],  15);
+       ROUND(cc, dd, aa, bb, F4, K4, in[12],  9);
+       ROUND(bb, cc, dd, aa, F4, K4, in[4],   8);
+       ROUND(aa, bb, cc, dd, F4, K4, in[13],  9);
+       ROUND(dd, aa, bb, cc, F4, K4, in[3],  14);
+       ROUND(cc, dd, aa, bb, F4, K4, in[7],   5);
+       ROUND(bb, cc, dd, aa, F4, K4, in[15],  6);
+       ROUND(aa, bb, cc, dd, F4, K4, in[14],  8);
+       ROUND(dd, aa, bb, cc, F4, K4, in[5],   6);
+       ROUND(cc, dd, aa, bb, F4, K4, in[6],   5);
+       ROUND(bb, cc, dd, aa, F4, K4, in[2],  12);
+
+       /* round 4: right lane */
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[8],  15);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[6],   5);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[4],   8);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[1],  11);
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[3],  14);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[11], 14);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[15],  6);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[0],  14);
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[5],   6);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[12],  9);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[2],  12);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[13],  9);
+       ROUND(aaa, bbb, ccc, ddd, F1, KK4, in[9],  12);
+       ROUND(ddd, aaa, bbb, ccc, F1, KK4, in[7],   5);
+       ROUND(ccc, ddd, aaa, bbb, F1, KK4, in[10], 15);
+       ROUND(bbb, ccc, ddd, aaa, F1, KK4, in[14],  8);
+
+       /* Swap contents of "d" registers */
+       tmp = dd; dd = ddd; ddd = tmp;
+
+       /* combine results */
+       state[0] += aa;
+       state[1] += bb;
+       state[2] += cc;
+       state[3] += dd;
+       state[4] += aaa;
+       state[5] += bbb;
+       state[6] += ccc;
+       state[7] += ddd;
+
+       return;
+}
+
+static void rmd256_init(struct crypto_tfm *tfm)
+{
+       struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm);
+
+       rctx->byte_count = 0;
+
+       rctx->state[0] = RMD_H0;
+       rctx->state[1] = RMD_H1;
+       rctx->state[2] = RMD_H2;
+       rctx->state[3] = RMD_H3;
+       rctx->state[4] = RMD_H5;
+       rctx->state[5] = RMD_H6;
+       rctx->state[6] = RMD_H7;
+       rctx->state[7] = RMD_H8;
+
+       memset(rctx->buffer, 0, sizeof(rctx->buffer));
+}
+
+static void rmd256_update(struct crypto_tfm *tfm, const u8 *data,
+                         unsigned int len)
+{
+       struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm);
+       const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
+
+       rctx->byte_count += len;
+
+       /* Enough space in buffer? If so copy and we're done */
+       if (avail > len) {
+               memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+                      data, len);
+               return;
+       }
+
+       memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+              data, avail);
+
+       rmd256_transform(rctx->state, rctx->buffer);
+       data += avail;
+       len -= avail;
+
+       while (len >= sizeof(rctx->buffer)) {
+               memcpy(rctx->buffer, data, sizeof(rctx->buffer));
+               rmd256_transform(rctx->state, rctx->buffer);
+               data += sizeof(rctx->buffer);
+               len -= sizeof(rctx->buffer);
+       }
+
+       memcpy(rctx->buffer, data, len);
+}
+
+/* Add padding and return the message digest. */
+static void rmd256_final(struct crypto_tfm *tfm, u8 *out)
+{
+       struct rmd256_ctx *rctx = crypto_tfm_ctx(tfm);
+       u32 i, index, padlen;
+       __le64 bits;
+       __le32 *dst = (__le32 *)out;
+       static const u8 padding[64] = { 0x80, };
+
+       bits = cpu_to_le64(rctx->byte_count << 3);
+
+       /* Pad out to 56 mod 64 */
+       index = rctx->byte_count & 0x3f;
+       padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+       rmd256_update(tfm, padding, padlen);
+
+       /* Append length */
+       rmd256_update(tfm, (const u8 *)&bits, sizeof(bits));
+
+       /* Store state in digest */
+       for (i = 0; i < 8; i++)
+               dst[i] = cpu_to_le32p(&rctx->state[i]);
+
+       /* Wipe context */
+       memset(rctx, 0, sizeof(*rctx));
+}
+
+static struct crypto_alg alg = {
+       .cra_name        =      "rmd256",
+       .cra_driver_name =      "rmd256",
+       .cra_flags       =      CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize   =      RMD256_BLOCK_SIZE,
+       .cra_ctxsize     =      sizeof(struct rmd256_ctx),
+       .cra_module      =      THIS_MODULE,
+       .cra_list        =      LIST_HEAD_INIT(alg.cra_list),
+       .cra_u           =      { .digest = {
+       .dia_digestsize  =      RMD256_DIGEST_SIZE,
+       .dia_init        =      rmd256_init,
+       .dia_update      =      rmd256_update,
+       .dia_final       =      rmd256_final } }
+};
+
+static int __init rmd256_mod_init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit rmd256_mod_fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(rmd256_mod_init);
+module_exit(rmd256_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RIPEMD-256 Message Digest");
+
+MODULE_ALIAS("rmd256");
diff --git a/crypto/rmd320.c b/crypto/rmd320.c
new file mode 100644 (file)
index 0000000..b143d66
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Cryptographic API.
+ *
+ * RIPEMD-320 - RACE Integrity Primitives Evaluation Message Digest.
+ *
+ * Based on the reference implementation by Antoon Bosselaers, ESAT-COSIC
+ *
+ * Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger (at) swiss-it.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/cryptohash.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include "ripemd.h"
+
+struct rmd320_ctx {
+       u64 byte_count;
+       u32 state[10];
+       __le32 buffer[16];
+};
+
+#define K1  RMD_K1
+#define K2  RMD_K2
+#define K3  RMD_K3
+#define K4  RMD_K4
+#define K5  RMD_K5
+#define KK1 RMD_K6
+#define KK2 RMD_K7
+#define KK3 RMD_K8
+#define KK4 RMD_K9
+#define KK5 RMD_K1
+
+#define F1(x, y, z) (x ^ y ^ z)                /* XOR */
+#define F2(x, y, z) (z ^ (x & (y ^ z)))        /* x ? y : z */
+#define F3(x, y, z) ((x | ~y) ^ z)
+#define F4(x, y, z) (y ^ (z & (x ^ y)))        /* z ? x : y */
+#define F5(x, y, z) (x ^ (y | ~z))
+
+#define ROUND(a, b, c, d, e, f, k, x, s)  { \
+       (a) += f((b), (c), (d)) + le32_to_cpup(&(x)) + (k); \
+       (a) = rol32((a), (s)) + (e); \
+       (c) = rol32((c), 10); \
+}
+
+static void rmd320_transform(u32 *state, const __le32 *in)
+{
+       u32 aa, bb, cc, dd, ee, aaa, bbb, ccc, ddd, eee, tmp;
+
+       /* Initialize left lane */
+       aa = state[0];
+       bb = state[1];
+       cc = state[2];
+       dd = state[3];
+       ee = state[4];
+
+       /* Initialize right lane */
+       aaa = state[5];
+       bbb = state[6];
+       ccc = state[7];
+       ddd = state[8];
+       eee = state[9];
+
+       /* round 1: left lane */
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[0],  11);
+       ROUND(ee, aa, bb, cc, dd, F1, K1, in[1],  14);
+       ROUND(dd, ee, aa, bb, cc, F1, K1, in[2],  15);
+       ROUND(cc, dd, ee, aa, bb, F1, K1, in[3],  12);
+       ROUND(bb, cc, dd, ee, aa, F1, K1, in[4],   5);
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[5],   8);
+       ROUND(ee, aa, bb, cc, dd, F1, K1, in[6],   7);
+       ROUND(dd, ee, aa, bb, cc, F1, K1, in[7],   9);
+       ROUND(cc, dd, ee, aa, bb, F1, K1, in[8],  11);
+       ROUND(bb, cc, dd, ee, aa, F1, K1, in[9],  13);
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[10], 14);
+       ROUND(ee, aa, bb, cc, dd, F1, K1, in[11], 15);
+       ROUND(dd, ee, aa, bb, cc, F1, K1, in[12],  6);
+       ROUND(cc, dd, ee, aa, bb, F1, K1, in[13],  7);
+       ROUND(bb, cc, dd, ee, aa, F1, K1, in[14],  9);
+       ROUND(aa, bb, cc, dd, ee, F1, K1, in[15],  8);
+
+       /* round 1: right lane */
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[5],   8);
+       ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[14],  9);
+       ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[7],   9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[0],  11);
+       ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[9],  13);
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[2],  15);
+       ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[11], 15);
+       ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[4],   5);
+       ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[13],  7);
+       ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[6],   7);
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[15],  8);
+       ROUND(eee, aaa, bbb, ccc, ddd, F5, KK1, in[8],  11);
+       ROUND(ddd, eee, aaa, bbb, ccc, F5, KK1, in[1],  14);
+       ROUND(ccc, ddd, eee, aaa, bbb, F5, KK1, in[10], 14);
+       ROUND(bbb, ccc, ddd, eee, aaa, F5, KK1, in[3],  12);
+       ROUND(aaa, bbb, ccc, ddd, eee, F5, KK1, in[12],  6);
+
+       /* Swap contents of "a" registers */
+       tmp = aa; aa = aaa; aaa = tmp;
+
+       /* round 2: left lane" */
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[7],   7);
+       ROUND(dd, ee, aa, bb, cc, F2, K2, in[4],   6);
+       ROUND(cc, dd, ee, aa, bb, F2, K2, in[13],  8);
+       ROUND(bb, cc, dd, ee, aa, F2, K2, in[1],  13);
+       ROUND(aa, bb, cc, dd, ee, F2, K2, in[10], 11);
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[6],   9);
+       ROUND(dd, ee, aa, bb, cc, F2, K2, in[15],  7);
+       ROUND(cc, dd, ee, aa, bb, F2, K2, in[3],  15);
+       ROUND(bb, cc, dd, ee, aa, F2, K2, in[12],  7);
+       ROUND(aa, bb, cc, dd, ee, F2, K2, in[0],  12);
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[9],  15);
+       ROUND(dd, ee, aa, bb, cc, F2, K2, in[5],   9);
+       ROUND(cc, dd, ee, aa, bb, F2, K2, in[2],  11);
+       ROUND(bb, cc, dd, ee, aa, F2, K2, in[14],  7);
+       ROUND(aa, bb, cc, dd, ee, F2, K2, in[11], 13);
+       ROUND(ee, aa, bb, cc, dd, F2, K2, in[8],  12);
+
+       /* round 2: right lane */
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[6],   9);
+       ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[11], 13);
+       ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[3],  15);
+       ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[7],   7);
+       ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[0],  12);
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[13],  8);
+       ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[5],   9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[10], 11);
+       ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[14],  7);
+       ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[15],  7);
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[8],  12);
+       ROUND(ddd, eee, aaa, bbb, ccc, F4, KK2, in[12],  7);
+       ROUND(ccc, ddd, eee, aaa, bbb, F4, KK2, in[4],   6);
+       ROUND(bbb, ccc, ddd, eee, aaa, F4, KK2, in[9],  15);
+       ROUND(aaa, bbb, ccc, ddd, eee, F4, KK2, in[1],  13);
+       ROUND(eee, aaa, bbb, ccc, ddd, F4, KK2, in[2],  11);
+
+       /* Swap contents of "b" registers */
+       tmp = bb; bb = bbb; bbb = tmp;
+
+       /* round 3: left lane" */
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[3],  11);
+       ROUND(cc, dd, ee, aa, bb, F3, K3, in[10], 13);
+       ROUND(bb, cc, dd, ee, aa, F3, K3, in[14],  6);
+       ROUND(aa, bb, cc, dd, ee, F3, K3, in[4],   7);
+       ROUND(ee, aa, bb, cc, dd, F3, K3, in[9],  14);
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[15],  9);
+       ROUND(cc, dd, ee, aa, bb, F3, K3, in[8],  13);
+       ROUND(bb, cc, dd, ee, aa, F3, K3, in[1],  15);
+       ROUND(aa, bb, cc, dd, ee, F3, K3, in[2],  14);
+       ROUND(ee, aa, bb, cc, dd, F3, K3, in[7],   8);
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[0],  13);
+       ROUND(cc, dd, ee, aa, bb, F3, K3, in[6],   6);
+       ROUND(bb, cc, dd, ee, aa, F3, K3, in[13],  5);
+       ROUND(aa, bb, cc, dd, ee, F3, K3, in[11], 12);
+       ROUND(ee, aa, bb, cc, dd, F3, K3, in[5],   7);
+       ROUND(dd, ee, aa, bb, cc, F3, K3, in[12],  5);
+
+       /* round 3: right lane */
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[15],  9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[5],   7);
+       ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[1],  15);
+       ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[3],  11);
+       ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[7],   8);
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[14],  6);
+       ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[6],   6);
+       ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[9],  14);
+       ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[11], 12);
+       ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[8],  13);
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[12],  5);
+       ROUND(ccc, ddd, eee, aaa, bbb, F3, KK3, in[2],  14);
+       ROUND(bbb, ccc, ddd, eee, aaa, F3, KK3, in[10], 13);
+       ROUND(aaa, bbb, ccc, ddd, eee, F3, KK3, in[0],  13);
+       ROUND(eee, aaa, bbb, ccc, ddd, F3, KK3, in[4],   7);
+       ROUND(ddd, eee, aaa, bbb, ccc, F3, KK3, in[13],  5);
+
+       /* Swap contents of "c" registers */
+       tmp = cc; cc = ccc; ccc = tmp;
+
+       /* round 4: left lane" */
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[1],  11);
+       ROUND(bb, cc, dd, ee, aa, F4, K4, in[9],  12);
+       ROUND(aa, bb, cc, dd, ee, F4, K4, in[11], 14);
+       ROUND(ee, aa, bb, cc, dd, F4, K4, in[10], 15);
+       ROUND(dd, ee, aa, bb, cc, F4, K4, in[0],  14);
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[8],  15);
+       ROUND(bb, cc, dd, ee, aa, F4, K4, in[12],  9);
+       ROUND(aa, bb, cc, dd, ee, F4, K4, in[4],   8);
+       ROUND(ee, aa, bb, cc, dd, F4, K4, in[13],  9);
+       ROUND(dd, ee, aa, bb, cc, F4, K4, in[3],  14);
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[7],   5);
+       ROUND(bb, cc, dd, ee, aa, F4, K4, in[15],  6);
+       ROUND(aa, bb, cc, dd, ee, F4, K4, in[14],  8);
+       ROUND(ee, aa, bb, cc, dd, F4, K4, in[5],   6);
+       ROUND(dd, ee, aa, bb, cc, F4, K4, in[6],   5);
+       ROUND(cc, dd, ee, aa, bb, F4, K4, in[2],  12);
+
+       /* round 4: right lane */
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[8],  15);
+       ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[6],   5);
+       ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[4],   8);
+       ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[1],  11);
+       ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[3],  14);
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[11], 14);
+       ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[15],  6);
+       ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[0],  14);
+       ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[5],   6);
+       ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[12],  9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[2],  12);
+       ROUND(bbb, ccc, ddd, eee, aaa, F2, KK4, in[13],  9);
+       ROUND(aaa, bbb, ccc, ddd, eee, F2, KK4, in[9],  12);
+       ROUND(eee, aaa, bbb, ccc, ddd, F2, KK4, in[7],   5);
+       ROUND(ddd, eee, aaa, bbb, ccc, F2, KK4, in[10], 15);
+       ROUND(ccc, ddd, eee, aaa, bbb, F2, KK4, in[14],  8);
+
+       /* Swap contents of "d" registers */
+       tmp = dd; dd = ddd; ddd = tmp;
+
+       /* round 5: left lane" */
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[4],   9);
+       ROUND(aa, bb, cc, dd, ee, F5, K5, in[0],  15);
+       ROUND(ee, aa, bb, cc, dd, F5, K5, in[5],   5);
+       ROUND(dd, ee, aa, bb, cc, F5, K5, in[9],  11);
+       ROUND(cc, dd, ee, aa, bb, F5, K5, in[7],   6);
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[12],  8);
+       ROUND(aa, bb, cc, dd, ee, F5, K5, in[2],  13);
+       ROUND(ee, aa, bb, cc, dd, F5, K5, in[10], 12);
+       ROUND(dd, ee, aa, bb, cc, F5, K5, in[14],  5);
+       ROUND(cc, dd, ee, aa, bb, F5, K5, in[1],  12);
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[3],  13);
+       ROUND(aa, bb, cc, dd, ee, F5, K5, in[8],  14);
+       ROUND(ee, aa, bb, cc, dd, F5, K5, in[11], 11);
+       ROUND(dd, ee, aa, bb, cc, F5, K5, in[6],   8);
+       ROUND(cc, dd, ee, aa, bb, F5, K5, in[15],  5);
+       ROUND(bb, cc, dd, ee, aa, F5, K5, in[13],  6);
+
+       /* round 5: right lane */
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[12],  8);
+       ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[15],  5);
+       ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[10], 12);
+       ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[4],   9);
+       ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[1],  12);
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[5],   5);
+       ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[8],  14);
+       ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[7],   6);
+       ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[6],   8);
+       ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[2],  13);
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[13],  6);
+       ROUND(aaa, bbb, ccc, ddd, eee, F1, KK5, in[14],  5);
+       ROUND(eee, aaa, bbb, ccc, ddd, F1, KK5, in[0],  15);
+       ROUND(ddd, eee, aaa, bbb, ccc, F1, KK5, in[3],  13);
+       ROUND(ccc, ddd, eee, aaa, bbb, F1, KK5, in[9],  11);
+       ROUND(bbb, ccc, ddd, eee, aaa, F1, KK5, in[11], 11);
+
+       /* Swap contents of "e" registers */
+       tmp = ee; ee = eee; eee = tmp;
+
+       /* combine results */
+       state[0] += aa;
+       state[1] += bb;
+       state[2] += cc;
+       state[3] += dd;
+       state[4] += ee;
+       state[5] += aaa;
+       state[6] += bbb;
+       state[7] += ccc;
+       state[8] += ddd;
+       state[9] += eee;
+
+       return;
+}
+
+static void rmd320_init(struct crypto_tfm *tfm)
+{
+       struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm);
+
+       rctx->byte_count = 0;
+
+       rctx->state[0] = RMD_H0;
+       rctx->state[1] = RMD_H1;
+       rctx->state[2] = RMD_H2;
+       rctx->state[3] = RMD_H3;
+       rctx->state[4] = RMD_H4;
+       rctx->state[5] = RMD_H5;
+       rctx->state[6] = RMD_H6;
+       rctx->state[7] = RMD_H7;
+       rctx->state[8] = RMD_H8;
+       rctx->state[9] = RMD_H9;
+
+       memset(rctx->buffer, 0, sizeof(rctx->buffer));
+}
+
+static void rmd320_update(struct crypto_tfm *tfm, const u8 *data,
+                         unsigned int len)
+{
+       struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm);
+       const u32 avail = sizeof(rctx->buffer) - (rctx->byte_count & 0x3f);
+
+       rctx->byte_count += len;
+
+       /* Enough space in buffer? If so copy and we're done */
+       if (avail > len) {
+               memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+                      data, len);
+               return;
+       }
+
+       memcpy((char *)rctx->buffer + (sizeof(rctx->buffer) - avail),
+              data, avail);
+
+       rmd320_transform(rctx->state, rctx->buffer);
+       data += avail;
+       len -= avail;
+
+       while (len >= sizeof(rctx->buffer)) {
+               memcpy(rctx->buffer, data, sizeof(rctx->buffer));
+               rmd320_transform(rctx->state, rctx->buffer);
+               data += sizeof(rctx->buffer);
+               len -= sizeof(rctx->buffer);
+       }
+
+       memcpy(rctx->buffer, data, len);
+}
+
+/* Add padding and return the message digest. */
+static void rmd320_final(struct crypto_tfm *tfm, u8 *out)
+{
+       struct rmd320_ctx *rctx = crypto_tfm_ctx(tfm);
+       u32 i, index, padlen;
+       __le64 bits;
+       __le32 *dst = (__le32 *)out;
+       static const u8 padding[64] = { 0x80, };
+
+       bits = cpu_to_le64(rctx->byte_count << 3);
+
+       /* Pad out to 56 mod 64 */
+       index = rctx->byte_count & 0x3f;
+       padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+       rmd320_update(tfm, padding, padlen);
+
+       /* Append length */
+       rmd320_update(tfm, (const u8 *)&bits, sizeof(bits));
+
+       /* Store state in digest */
+       for (i = 0; i < 10; i++)
+               dst[i] = cpu_to_le32p(&rctx->state[i]);
+
+       /* Wipe context */
+       memset(rctx, 0, sizeof(*rctx));
+}
+
+static struct crypto_alg alg = {
+       .cra_name        =      "rmd320",
+       .cra_driver_name =      "rmd320",
+       .cra_flags       =      CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize   =      RMD320_BLOCK_SIZE,
+       .cra_ctxsize     =      sizeof(struct rmd320_ctx),
+       .cra_module      =      THIS_MODULE,
+       .cra_list        =      LIST_HEAD_INIT(alg.cra_list),
+       .cra_u           =      { .digest = {
+       .dia_digestsize  =      RMD320_DIGEST_SIZE,
+       .dia_init        =      rmd320_init,
+       .dia_update      =      rmd320_update,
+       .dia_final       =      rmd320_final } }
+};
+
+static int __init rmd320_mod_init(void)
+{
+       return crypto_register_alg(&alg);
+}
+
+static void __exit rmd320_mod_fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(rmd320_mod_init);
+module_exit(rmd320_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RIPEMD-320 Message Digest");
+
+MODULE_ALIAS("rmd320");
index e47f6e02133c155622d477567d88f890489f151f..59821a22d75238e568fc07dff1b1d6e73f804640 100644 (file)
  * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  *
- * 2007-11-13 Added GCM tests
- * 2007-11-13 Added AEAD support
- * 2007-11-06 Added SHA-224 and SHA-224-HMAC tests
- * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
- * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>)
- * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt
- *
  */
 
+#include <crypto/hash.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -30,7 +24,6 @@
 #include <linux/scatterlist.h>
 #include <linux/string.h>
 #include <linux/crypto.h>
-#include <linux/highmem.h>
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 #include <linux/timex.h>
@@ -38,7 +31,7 @@
 #include "tcrypt.h"
 
 /*
- * Need to kmalloc() memory for testing kmap().
+ * Need to kmalloc() memory for testing.
  */
 #define TVMEMSIZE      16384
 #define XBUFSIZE       32768
@@ -46,7 +39,7 @@
 /*
  * Indexes into the xbuf to simulate cross-page access.
  */
-#define IDX1           37
+#define IDX1           32
 #define IDX2           32400
 #define IDX3           1
 #define IDX4           8193
@@ -83,7 +76,8 @@ static char *check[] = {
        "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes",
        "cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
        "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",
-       "camellia", "seed", "salsa20", "lzo", "cts", NULL
+       "camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320",
+       "lzo", "cts", NULL
 };
 
 static void hexdump(unsigned char *buf, unsigned int len)
@@ -110,22 +104,30 @@ static void test_hash(char *algo, struct hash_testvec *template,
        unsigned int i, j, k, temp;
        struct scatterlist sg[8];
        char result[64];
-       struct crypto_hash *tfm;
-       struct hash_desc desc;
+       struct crypto_ahash *tfm;
+       struct ahash_request *req;
+       struct tcrypt_result tresult;
        int ret;
        void *hash_buff;
 
        printk("\ntesting %s\n", algo);
 
-       tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
+       init_completion(&tresult.completion);
+
+       tfm = crypto_alloc_ahash(algo, 0, 0);
        if (IS_ERR(tfm)) {
                printk("failed to load transform for %s: %ld\n", algo,
                       PTR_ERR(tfm));
                return;
        }
 
-       desc.tfm = tfm;
-       desc.flags = 0;
+       req = ahash_request_alloc(tfm, GFP_KERNEL);
+       if (!req) {
+               printk(KERN_ERR "failed to allocate request for %s\n", algo);
+               goto out_noreq;
+       }
+       ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                  tcrypt_complete, &tresult);
 
        for (i = 0; i < tcount; i++) {
                printk("test %u:\n", i + 1);
@@ -139,8 +141,9 @@ static void test_hash(char *algo, struct hash_testvec *template,
                sg_init_one(&sg[0], hash_buff, template[i].psize);
 
                if (template[i].ksize) {
-                       ret = crypto_hash_setkey(tfm, template[i].key,
-                                                template[i].ksize);
+                       crypto_ahash_clear_flags(tfm, ~0);
+                       ret = crypto_ahash_setkey(tfm, template[i].key,
+                                                 template[i].ksize);
                        if (ret) {
                                printk("setkey() failed ret=%d\n", ret);
                                kfree(hash_buff);
@@ -148,17 +151,30 @@ static void test_hash(char *algo, struct hash_testvec *template,
                        }
                }
 
-               ret = crypto_hash_digest(&desc, sg, template[i].psize, result);
-               if (ret) {
+               ahash_request_set_crypt(req, sg, result, template[i].psize);
+               ret = crypto_ahash_digest(req);
+               switch (ret) {
+               case 0:
+                       break;
+               case -EINPROGRESS:
+               case -EBUSY:
+                       ret = wait_for_completion_interruptible(
+                               &tresult.completion);
+                       if (!ret && !(ret = tresult.err)) {
+                               INIT_COMPLETION(tresult.completion);
+                               break;
+                       }
+                       /* fall through */
+               default:
                        printk("digest () failed ret=%d\n", ret);
                        kfree(hash_buff);
                        goto out;
                }
 
-               hexdump(result, crypto_hash_digestsize(tfm));
+               hexdump(result, crypto_ahash_digestsize(tfm));
                printk("%s\n",
                       memcmp(result, template[i].digest,
-                             crypto_hash_digestsize(tfm)) ?
+                             crypto_ahash_digestsize(tfm)) ?
                       "fail" : "pass");
                kfree(hash_buff);
        }
@@ -187,8 +203,9 @@ static void test_hash(char *algo, struct hash_testvec *template,
                        }
 
                        if (template[i].ksize) {
-                               ret = crypto_hash_setkey(tfm, template[i].key,
-                                                        template[i].ksize);
+                               crypto_ahash_clear_flags(tfm, ~0);
+                               ret = crypto_ahash_setkey(tfm, template[i].key,
+                                                         template[i].ksize);
 
                                if (ret) {
                                        printk("setkey() failed ret=%d\n", ret);
@@ -196,29 +213,44 @@ static void test_hash(char *algo, struct hash_testvec *template,
                                }
                        }
 
-                       ret = crypto_hash_digest(&desc, sg, template[i].psize,
-                                                result);
-                       if (ret) {
+                       ahash_request_set_crypt(req, sg, result,
+                                               template[i].psize);
+                       ret = crypto_ahash_digest(req);
+                       switch (ret) {
+                       case 0:
+                               break;
+                       case -EINPROGRESS:
+                       case -EBUSY:
+                               ret = wait_for_completion_interruptible(
+                                       &tresult.completion);
+                               if (!ret && !(ret = tresult.err)) {
+                                       INIT_COMPLETION(tresult.completion);
+                                       break;
+                               }
+                               /* fall through */
+                       default:
                                printk("digest () failed ret=%d\n", ret);
                                goto out;
                        }
 
-                       hexdump(result, crypto_hash_digestsize(tfm));
+                       hexdump(result, crypto_ahash_digestsize(tfm));
                        printk("%s\n",
                               memcmp(result, template[i].digest,
-                                     crypto_hash_digestsize(tfm)) ?
+                                     crypto_ahash_digestsize(tfm)) ?
                               "fail" : "pass");
                }
        }
 
 out:
-       crypto_free_hash(tfm);
+       ahash_request_free(req);
+out_noreq:
+       crypto_free_ahash(tfm);
 }
 
 static void test_aead(char *algo, int enc, struct aead_testvec *template,
                      unsigned int tcount)
 {
-       unsigned int ret, i, j, k, temp;
+       unsigned int ret, i, j, k, n, temp;
        char *q;
        struct crypto_aead *tfm;
        char *key;
@@ -344,13 +376,12 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,
                                goto next_one;
                        }
 
-                       q = kmap(sg_page(&sg[0])) + sg[0].offset;
+                       q = input;
                        hexdump(q, template[i].rlen);
 
                        printk(KERN_INFO "enc/dec: %s\n",
                               memcmp(q, template[i].result,
                                      template[i].rlen) ? "fail" : "pass");
-                       kunmap(sg_page(&sg[0]));
 next_one:
                        if (!template[i].key)
                                kfree(key);
@@ -360,7 +391,6 @@ next_one:
        }
 
        printk(KERN_INFO "\ntesting %s %s across pages (chunking)\n", algo, e);
-       memset(xbuf, 0, XBUFSIZE);
        memset(axbuf, 0, XBUFSIZE);
 
        for (i = 0, j = 0; i < tcount; i++) {
@@ -388,6 +418,7 @@ next_one:
                                        goto out;
                        }
 
+                       memset(xbuf, 0, XBUFSIZE);
                        sg_init_table(sg, template[i].np);
                        for (k = 0, temp = 0; k < template[i].np; k++) {
                                memcpy(&xbuf[IDX[k]],
@@ -450,7 +481,7 @@ next_one:
 
                        for (k = 0, temp = 0; k < template[i].np; k++) {
                                printk(KERN_INFO "page %u\n", k);
-                               q = kmap(sg_page(&sg[k])) + sg[k].offset;
+                               q = &axbuf[IDX[k]];
                                hexdump(q, template[i].tap[k]);
                                printk(KERN_INFO "%s\n",
                                       memcmp(q, template[i].result + temp,
@@ -459,8 +490,15 @@ next_one:
                                               0 : authsize)) ?
                                       "fail" : "pass");
 
+                               for (n = 0; q[template[i].tap[k] + n]; n++)
+                                       ;
+                               if (n) {
+                                       printk("Result buffer corruption %u "
+                                              "bytes:\n", n);
+                                       hexdump(&q[template[i].tap[k]], n);
+                               }
+
                                temp += template[i].tap[k];
-                               kunmap(sg_page(&sg[k]));
                        }
                }
        }
@@ -473,7 +511,7 @@ out:
 static void test_cipher(char *algo, int enc,
                        struct cipher_testvec *template, unsigned int tcount)
 {
-       unsigned int ret, i, j, k, temp;
+       unsigned int ret, i, j, k, n, temp;
        char *q;
        struct crypto_ablkcipher *tfm;
        struct ablkcipher_request *req;
@@ -569,19 +607,17 @@ static void test_cipher(char *algo, int enc,
                                goto out;
                        }
 
-                       q = kmap(sg_page(&sg[0])) + sg[0].offset;
+                       q = data;
                        hexdump(q, template[i].rlen);
 
                        printk("%s\n",
                               memcmp(q, template[i].result,
                                      template[i].rlen) ? "fail" : "pass");
-                       kunmap(sg_page(&sg[0]));
                }
                kfree(data);
        }
 
        printk("\ntesting %s %s across pages (chunking)\n", algo, e);
-       memset(xbuf, 0, XBUFSIZE);
 
        j = 0;
        for (i = 0; i < tcount; i++) {
@@ -596,6 +632,7 @@ static void test_cipher(char *algo, int enc,
                        printk("test %u (%d bit key):\n",
                        j, template[i].klen * 8);
 
+                       memset(xbuf, 0, XBUFSIZE);
                        crypto_ablkcipher_clear_flags(tfm, ~0);
                        if (template[i].wk)
                                crypto_ablkcipher_set_flags(
@@ -649,14 +686,21 @@ static void test_cipher(char *algo, int enc,
                        temp = 0;
                        for (k = 0; k < template[i].np; k++) {
                                printk("page %u\n", k);
-                               q = kmap(sg_page(&sg[k])) + sg[k].offset;
+                               q = &xbuf[IDX[k]];
                                hexdump(q, template[i].tap[k]);
                                printk("%s\n",
                                        memcmp(q, template[i].result + temp,
                                                template[i].tap[k]) ? "fail" :
                                        "pass");
+
+                               for (n = 0; q[template[i].tap[k] + n]; n++)
+                                       ;
+                               if (n) {
+                                       printk("Result buffer corruption %u "
+                                              "bytes:\n", n);
+                                       hexdump(&q[template[i].tap[k]], n);
+                               }
                                temp += template[i].tap[k];
-                               kunmap(sg_page(&sg[k]));
                        }
                }
        }
@@ -1172,6 +1216,14 @@ static void do_test(void)
                test_cipher("ecb(des3_ede)", DECRYPT, des3_ede_dec_tv_template,
                            DES3_EDE_DEC_TEST_VECTORS);
 
+               test_cipher("cbc(des3_ede)", ENCRYPT,
+                           des3_ede_cbc_enc_tv_template,
+                           DES3_EDE_CBC_ENC_TEST_VECTORS);
+
+               test_cipher("cbc(des3_ede)", DECRYPT,
+                           des3_ede_cbc_dec_tv_template,
+                           DES3_EDE_CBC_DEC_TEST_VECTORS);
+
                test_hash("md4", md4_tv_template, MD4_TEST_VECTORS);
 
                test_hash("sha224", sha224_tv_template, SHA224_TEST_VECTORS);
@@ -1382,6 +1434,14 @@ static void do_test(void)
                            DES3_EDE_ENC_TEST_VECTORS);
                test_cipher("ecb(des3_ede)", DECRYPT, des3_ede_dec_tv_template,
                            DES3_EDE_DEC_TEST_VECTORS);
+
+               test_cipher("cbc(des3_ede)", ENCRYPT,
+                           des3_ede_cbc_enc_tv_template,
+                           DES3_EDE_CBC_ENC_TEST_VECTORS);
+
+               test_cipher("cbc(des3_ede)", DECRYPT,
+                           des3_ede_cbc_dec_tv_template,
+                           DES3_EDE_CBC_DEC_TEST_VECTORS);
                break;
 
        case 5:
@@ -1550,7 +1610,7 @@ static void do_test(void)
        case 29:
                test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS);
                break;
-               
+
        case 30:
                test_cipher("ecb(xeta)", ENCRYPT, xeta_enc_tv_template,
                            XETA_ENC_TEST_VECTORS);
@@ -1615,6 +1675,22 @@ static void do_test(void)
                            CTS_MODE_DEC_TEST_VECTORS);
                break;
 
+        case 39:
+               test_hash("rmd128", rmd128_tv_template, RMD128_TEST_VECTORS);
+               break;
+
+        case 40:
+               test_hash("rmd160", rmd160_tv_template, RMD160_TEST_VECTORS);
+               break;
+
+       case 41:
+               test_hash("rmd256", rmd256_tv_template, RMD256_TEST_VECTORS);
+               break;
+
+       case 42:
+               test_hash("rmd320", rmd320_tv_template, RMD320_TEST_VECTORS);
+               break;
+
        case 100:
                test_hash("hmac(md5)", hmac_md5_tv_template,
                          HMAC_MD5_TEST_VECTORS);
@@ -1650,6 +1726,16 @@ static void do_test(void)
                          XCBC_AES_TEST_VECTORS);
                break;
 
+       case 107:
+               test_hash("hmac(rmd128)", hmac_rmd128_tv_template,
+                         HMAC_RMD128_TEST_VECTORS);
+               break;
+
+       case 108:
+               test_hash("hmac(rmd160)", hmac_rmd160_tv_template,
+                         HMAC_RMD160_TEST_VECTORS);
+               break;
+
        case 200:
                test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
                                speed_template_16_24_32);
@@ -1788,6 +1874,22 @@ static void do_test(void)
                test_hash_speed("sha224", sec, generic_hash_speed_template);
                if (mode > 300 && mode < 400) break;
 
+       case 314:
+               test_hash_speed("rmd128", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 315:
+               test_hash_speed("rmd160", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 316:
+               test_hash_speed("rmd256", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+
+       case 317:
+               test_hash_speed("rmd320", sec, generic_hash_speed_template);
+               if (mode > 300 && mode < 400) break;
+
        case 399:
                break;
 
index 47bc0ecb89787e006fd92e51d229b1edd2880ea7..801e0c288862cb3fa2072416b684d959acf0424a 100644 (file)
  * Software Foundation; either version 2 of the License, or (at your option)
  * any later version.
  *
- * 2007-11-13 Added GCM tests
- * 2007-11-13 Added AEAD support
- * 2006-12-07 Added SHA384 HMAC and SHA512 HMAC tests
- * 2004-08-09 Cipher speed tests by Reyk Floeter <reyk@vantronix.net>
- * 2003-09-14 Changes by Kartikey Mahendra Bhatt
- *
  */
 #ifndef _CRYPTO_TCRYPT_H
 #define _CRYPTO_TCRYPT_H
@@ -168,6 +162,271 @@ static struct hash_testvec md5_tv_template[] = {
                .digest = "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
                          "\xac\x49\xda\x2e\x21\x07\xb6\x7a",
        }
+
+};
+
+/*
+ * RIPEMD-128 test vectors from ISO/IEC 10118-3:2004(E)
+ */
+#define RMD128_TEST_VECTORS     10
+
+static struct hash_testvec rmd128_tv_template[] = {
+       {
+               .digest = "\xcd\xf2\x62\x13\xa1\x50\xdc\x3e"
+                         "\xcb\x61\x0f\x18\xf6\xb3\x8b\x46",
+       }, {
+               .plaintext = "a",
+               .psize  = 1,
+               .digest = "\x86\xbe\x7a\xfa\x33\x9d\x0f\xc7"
+                         "\xcf\xc7\x85\xe7\x2f\x57\x8d\x33",
+       }, {
+               .plaintext = "abc",
+               .psize  = 3,
+               .digest = "\xc1\x4a\x12\x19\x9c\x66\xe4\xba"
+                         "\x84\x63\x6b\x0f\x69\x14\x4c\x77",
+       }, {
+               .plaintext = "message digest",
+               .psize  = 14,
+               .digest = "\x9e\x32\x7b\x3d\x6e\x52\x30\x62"
+                         "\xaf\xc1\x13\x2d\x7d\xf9\xd1\xb8",
+       }, {
+               .plaintext = "abcdefghijklmnopqrstuvwxyz",
+               .psize  = 26,
+               .digest = "\xfd\x2a\xa6\x07\xf7\x1d\xc8\xf5"
+                         "\x10\x71\x49\x22\xb3\x71\x83\x4e",
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+                            "fghijklmnopqrstuvwxyz0123456789",
+               .psize  = 62,
+               .digest = "\xd1\xe9\x59\xeb\x17\x9c\x91\x1f"
+                         "\xae\xa4\x62\x4c\x60\xc5\xc7\x02",
+       }, {
+               .plaintext = "1234567890123456789012345678901234567890"
+                            "1234567890123456789012345678901234567890",
+               .psize  = 80,
+               .digest = "\x3f\x45\xef\x19\x47\x32\xc2\xdb"
+                         "\xb2\xc4\xa2\xc7\x69\x79\x5f\xa3",
+        }, {
+               .plaintext = "abcdbcdecdefdefgefghfghighij"
+                            "hijkijkljklmklmnlmnomnopnopq",
+               .psize  = 56,
+               .digest = "\xa1\xaa\x06\x89\xd0\xfa\xfa\x2d"
+                         "\xdc\x22\xe8\x8b\x49\x13\x3a\x06",
+               .np     = 2,
+               .tap    = { 28, 28 },
+       }, {
+               .plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
+                            "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqr"
+                            "lmnopqrsmnopqrstnopqrstu",
+               .psize  = 112,
+               .digest = "\xd4\xec\xc9\x13\xe1\xdf\x77\x6b"
+                         "\xf4\x8d\xe9\xd5\x5b\x1f\x25\x46",
+       }, {
+               .plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+               .psize  = 32,
+               .digest = "\x13\xfc\x13\xe8\xef\xff\x34\x7d"
+                         "\xe1\x93\xff\x46\xdb\xac\xcf\xd4",
+       }
+};
+
+/*
+ * RIPEMD-160 test vectors from ISO/IEC 10118-3:2004(E)
+ */
+#define RMD160_TEST_VECTORS     10
+
+static struct hash_testvec rmd160_tv_template[] = {
+       {
+               .digest = "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28"
+                         "\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31",
+       }, {
+               .plaintext = "a",
+               .psize  = 1,
+               .digest = "\x0b\xdc\x9d\x2d\x25\x6b\x3e\xe9\xda\xae"
+                         "\x34\x7b\xe6\xf4\xdc\x83\x5a\x46\x7f\xfe",
+       }, {
+               .plaintext = "abc",
+               .psize  = 3,
+               .digest = "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04"
+                         "\x4a\x8e\x98\xc6\xb0\x87\xf1\x5a\x0b\xfc",
+       }, {
+               .plaintext = "message digest",
+               .psize  = 14,
+               .digest = "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8"
+                         "\x81\xb1\x23\xa8\x5f\xfa\x21\x59\x5f\x36",
+       }, {
+               .plaintext = "abcdefghijklmnopqrstuvwxyz",
+               .psize  = 26,
+               .digest = "\xf7\x1c\x27\x10\x9c\x69\x2c\x1b\x56\xbb"
+                         "\xdc\xeb\x5b\x9d\x28\x65\xb3\x70\x8d\xbc",
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+                            "fghijklmnopqrstuvwxyz0123456789",
+               .psize  = 62,
+               .digest = "\xb0\xe2\x0b\x6e\x31\x16\x64\x02\x86\xed"
+                         "\x3a\x87\xa5\x71\x30\x79\xb2\x1f\x51\x89",
+       }, {
+               .plaintext = "1234567890123456789012345678901234567890"
+                            "1234567890123456789012345678901234567890",
+               .psize  = 80,
+               .digest = "\x9b\x75\x2e\x45\x57\x3d\x4b\x39\xf4\xdb"
+                         "\xd3\x32\x3c\xab\x82\xbf\x63\x32\x6b\xfb",
+        }, {
+               .plaintext = "abcdbcdecdefdefgefghfghighij"
+                            "hijkijkljklmklmnlmnomnopnopq",
+               .psize  = 56,
+               .digest = "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05"
+                         "\xa0\x6c\x27\xdc\xf4\x9a\xda\x62\xeb\x2b",
+               .np     = 2,
+               .tap    = { 28, 28 },
+       }, {
+               .plaintext = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
+                            "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqr"
+                            "lmnopqrsmnopqrstnopqrstu",
+               .psize  = 112,
+               .digest = "\x6f\x3f\xa3\x9b\x6b\x50\x3c\x38\x4f\x91"
+                         "\x9a\x49\xa7\xaa\x5c\x2c\x08\xbd\xfb\x45",
+       }, {
+               .plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+               .psize  = 32,
+               .digest = "\x94\xc2\x64\x11\x54\x04\xe6\x33\x79\x0d"
+                         "\xfc\xc8\x7b\x58\x7d\x36\x77\x06\x7d\x9f",
+       }
+};
+
+/*
+ * RIPEMD-256 test vectors
+ */
+#define RMD256_TEST_VECTORS     8
+
+static struct hash_testvec rmd256_tv_template[] = {
+       {
+               .digest = "\x02\xba\x4c\x4e\x5f\x8e\xcd\x18"
+                         "\x77\xfc\x52\xd6\x4d\x30\xe3\x7a"
+                         "\x2d\x97\x74\xfb\x1e\x5d\x02\x63"
+                         "\x80\xae\x01\x68\xe3\xc5\x52\x2d",
+       }, {
+               .plaintext = "a",
+               .psize  = 1,
+               .digest = "\xf9\x33\x3e\x45\xd8\x57\xf5\xd9"
+                         "\x0a\x91\xba\xb7\x0a\x1e\xba\x0c"
+                         "\xfb\x1b\xe4\xb0\x78\x3c\x9a\xcf"
+                         "\xcd\x88\x3a\x91\x34\x69\x29\x25",
+       }, {
+               .plaintext = "abc",
+               .psize  = 3,
+               .digest = "\xaf\xbd\x6e\x22\x8b\x9d\x8c\xbb"
+                         "\xce\xf5\xca\x2d\x03\xe6\xdb\xa1"
+                         "\x0a\xc0\xbc\x7d\xcb\xe4\x68\x0e"
+                         "\x1e\x42\xd2\xe9\x75\x45\x9b\x65",
+       }, {
+               .plaintext = "message digest",
+               .psize  = 14,
+               .digest = "\x87\xe9\x71\x75\x9a\x1c\xe4\x7a"
+                         "\x51\x4d\x5c\x91\x4c\x39\x2c\x90"
+                         "\x18\xc7\xc4\x6b\xc1\x44\x65\x55"
+                         "\x4a\xfc\xdf\x54\xa5\x07\x0c\x0e",
+       }, {
+               .plaintext = "abcdefghijklmnopqrstuvwxyz",
+               .psize  = 26,
+               .digest = "\x64\x9d\x30\x34\x75\x1e\xa2\x16"
+                         "\x77\x6b\xf9\xa1\x8a\xcc\x81\xbc"
+                         "\x78\x96\x11\x8a\x51\x97\x96\x87"
+                         "\x82\xdd\x1f\xd9\x7d\x8d\x51\x33",
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+                            "fghijklmnopqrstuvwxyz0123456789",
+               .psize  = 62,
+               .digest = "\x57\x40\xa4\x08\xac\x16\xb7\x20"
+                         "\xb8\x44\x24\xae\x93\x1c\xbb\x1f"
+                         "\xe3\x63\xd1\xd0\xbf\x40\x17\xf1"
+                         "\xa8\x9f\x7e\xa6\xde\x77\xa0\xb8",
+       }, {
+               .plaintext = "1234567890123456789012345678901234567890"
+                            "1234567890123456789012345678901234567890",
+               .psize  = 80,
+               .digest = "\x06\xfd\xcc\x7a\x40\x95\x48\xaa"
+                         "\xf9\x13\x68\xc0\x6a\x62\x75\xb5"
+                         "\x53\xe3\xf0\x99\xbf\x0e\xa4\xed"
+                         "\xfd\x67\x78\xdf\x89\xa8\x90\xdd",
+        }, {
+               .plaintext = "abcdbcdecdefdefgefghfghighij"
+                            "hijkijkljklmklmnlmnomnopnopq",
+               .psize  = 56,
+               .digest = "\x38\x43\x04\x55\x83\xaa\xc6\xc8"
+                         "\xc8\xd9\x12\x85\x73\xe7\xa9\x80"
+                         "\x9a\xfb\x2a\x0f\x34\xcc\xc3\x6e"
+                         "\xa9\xe7\x2f\x16\xf6\x36\x8e\x3f",
+               .np     = 2,
+               .tap    = { 28, 28 },
+       }
+};
+
+/*
+ * RIPEMD-320 test vectors
+ */
+#define RMD320_TEST_VECTORS     8
+
+static struct hash_testvec rmd320_tv_template[] = {
+       {
+               .digest = "\x22\xd6\x5d\x56\x61\x53\x6c\xdc\x75\xc1"
+                         "\xfd\xf5\xc6\xde\x7b\x41\xb9\xf2\x73\x25"
+                         "\xeb\xc6\x1e\x85\x57\x17\x7d\x70\x5a\x0e"
+                         "\xc8\x80\x15\x1c\x3a\x32\xa0\x08\x99\xb8",
+       }, {
+               .plaintext = "a",
+               .psize  = 1,
+               .digest = "\xce\x78\x85\x06\x38\xf9\x26\x58\xa5\xa5"
+                         "\x85\x09\x75\x79\x92\x6d\xda\x66\x7a\x57"
+                         "\x16\x56\x2c\xfc\xf6\xfb\xe7\x7f\x63\x54"
+                         "\x2f\x99\xb0\x47\x05\xd6\x97\x0d\xff\x5d",
+       }, {
+               .plaintext = "abc",
+               .psize  = 3,
+               .digest = "\xde\x4c\x01\xb3\x05\x4f\x89\x30\xa7\x9d"
+                         "\x09\xae\x73\x8e\x92\x30\x1e\x5a\x17\x08"
+                         "\x5b\xef\xfd\xc1\xb8\xd1\x16\x71\x3e\x74"
+                         "\xf8\x2f\xa9\x42\xd6\x4c\xdb\xc4\x68\x2d",
+       }, {
+               .plaintext = "message digest",
+               .psize  = 14,
+               .digest = "\x3a\x8e\x28\x50\x2e\xd4\x5d\x42\x2f\x68"
+                         "\x84\x4f\x9d\xd3\x16\xe7\xb9\x85\x33\xfa"
+                         "\x3f\x2a\x91\xd2\x9f\x84\xd4\x25\xc8\x8d"
+                         "\x6b\x4e\xff\x72\x7d\xf6\x6a\x7c\x01\x97",
+       }, {
+               .plaintext = "abcdefghijklmnopqrstuvwxyz",
+               .psize  = 26,
+               .digest = "\xca\xbd\xb1\x81\x0b\x92\x47\x0a\x20\x93"
+                         "\xaa\x6b\xce\x05\x95\x2c\x28\x34\x8c\xf4"
+                         "\x3f\xf6\x08\x41\x97\x51\x66\xbb\x40\xed"
+                         "\x23\x40\x04\xb8\x82\x44\x63\xe6\xb0\x09",
+       }, {
+               .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
+                            "fghijklmnopqrstuvwxyz0123456789",
+               .psize  = 62,
+               .digest = "\xed\x54\x49\x40\xc8\x6d\x67\xf2\x50\xd2"
+                         "\x32\xc3\x0b\x7b\x3e\x57\x70\xe0\xc6\x0c"
+                         "\x8c\xb9\xa4\xca\xfe\x3b\x11\x38\x8a\xf9"
+                         "\x92\x0e\x1b\x99\x23\x0b\x84\x3c\x86\xa4",
+       }, {
+               .plaintext = "1234567890123456789012345678901234567890"
+                            "1234567890123456789012345678901234567890",
+               .psize  = 80,
+               .digest = "\x55\x78\x88\xaf\x5f\x6d\x8e\xd6\x2a\xb6"
+                         "\x69\x45\xc6\xd2\xa0\xa4\x7e\xcd\x53\x41"
+                         "\xe9\x15\xeb\x8f\xea\x1d\x05\x24\x95\x5f"
+                         "\x82\x5d\xc7\x17\xe4\xa0\x08\xab\x2d\x42",
+        }, {
+               .plaintext = "abcdbcdecdefdefgefghfghighij"
+                            "hijkijkljklmklmnlmnomnopnopq",
+               .psize  = 56,
+               .digest = "\xd0\x34\xa7\x95\x0c\xf7\x22\x02\x1b\xa4"
+                         "\xb8\x4d\xf7\x69\xa5\xde\x20\x60\xe2\x59"
+                         "\xdf\x4c\x9b\xb4\xa4\x26\x8c\x0e\x93\x5b"
+                         "\xbc\x74\x70\xa9\x69\xc9\xd0\x72\xa1\xac",
+               .np     = 2,
+               .tap    = { 28, 28 },
+       }
 };
 
 /*
@@ -816,6 +1075,168 @@ static struct hash_testvec hmac_md5_tv_template[] =
        },
 };
 
+/*
+ * HMAC-RIPEMD128 test vectors from RFC2286
+ */
+#define HMAC_RMD128_TEST_VECTORS       7
+
+static struct hash_testvec hmac_rmd128_tv_template[] = {
+       {
+               .key    = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+               .ksize  = 16,
+               .plaintext = "Hi There",
+               .psize  = 8,
+               .digest = "\xfb\xf6\x1f\x94\x92\xaa\x4b\xbf"
+                         "\x81\xc1\x72\xe8\x4e\x07\x34\xdb",
+       }, {
+               .key    = "Jefe",
+               .ksize  = 4,
+               .plaintext = "what do ya want for nothing?",
+               .psize  = 28,
+               .digest = "\x87\x5f\x82\x88\x62\xb6\xb3\x34"
+                         "\xb4\x27\xc5\x5f\x9f\x7f\xf0\x9b",
+               .np     = 2,
+               .tap    = { 14, 14 },
+       }, {
+               .key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+               .ksize  = 16,
+               .plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+                       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+                       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+                       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+               .psize  = 50,
+               .digest = "\x09\xf0\xb2\x84\x6d\x2f\x54\x3d"
+                         "\xa3\x63\xcb\xec\x8d\x62\xa3\x8d",
+       }, {
+               .key    = "\x01\x02\x03\x04\x05\x06\x07\x08"
+                         "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+                         "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+               .ksize  = 25,
+               .plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+                       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+                       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+                       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+               .psize  = 50,
+               .digest = "\xbd\xbb\xd7\xcf\x03\xe4\x4b\x5a"
+                         "\xa6\x0a\xf8\x15\xbe\x4d\x22\x94",
+       }, {
+               .key    = "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+               .ksize  = 16,
+               .plaintext = "Test With Truncation",
+               .psize  = 20,
+               .digest = "\xe7\x98\x08\xf2\x4b\x25\xfd\x03"
+                         "\x1c\x15\x5f\x0d\x55\x1d\x9a\x3a",
+       }, {
+               .key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa",
+               .ksize  = 80,
+               .plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+               .psize  = 54,
+               .digest = "\xdc\x73\x29\x28\xde\x98\x10\x4a"
+                         "\x1f\x59\xd3\x73\xc1\x50\xac\xbb",
+       }, {
+               .key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa",
+               .ksize  = 80,
+               .plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
+                          "Block-Size Data",
+               .psize  = 73,
+               .digest = "\x5c\x6b\xec\x96\x79\x3e\x16\xd4"
+                         "\x06\x90\xc2\x37\x63\x5f\x30\xc5",
+       },
+};
+
+/*
+ * HMAC-RIPEMD160 test vectors from RFC2286
+ */
+#define HMAC_RMD160_TEST_VECTORS       7
+
+static struct hash_testvec hmac_rmd160_tv_template[] = {
+       {
+               .key    = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+               .ksize  = 20,
+               .plaintext = "Hi There",
+               .psize  = 8,
+               .digest = "\x24\xcb\x4b\xd6\x7d\x20\xfc\x1a\x5d\x2e"
+                         "\xd7\x73\x2d\xcc\x39\x37\x7f\x0a\x56\x68",
+       }, {
+               .key    = "Jefe",
+               .ksize  = 4,
+               .plaintext = "what do ya want for nothing?",
+               .psize  = 28,
+               .digest = "\xdd\xa6\xc0\x21\x3a\x48\x5a\x9e\x24\xf4"
+                         "\x74\x20\x64\xa7\xf0\x33\xb4\x3c\x40\x69",
+               .np     = 2,
+               .tap    = { 14, 14 },
+       }, {
+               .key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+               .ksize  = 20,
+               .plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+                       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+                       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"
+                       "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+               .psize  = 50,
+               .digest = "\xb0\xb1\x05\x36\x0d\xe7\x59\x96\x0a\xb4"
+                         "\xf3\x52\x98\xe1\x16\xe2\x95\xd8\xe7\xc1",
+       }, {
+               .key    = "\x01\x02\x03\x04\x05\x06\x07\x08"
+                         "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+                         "\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+               .ksize  = 25,
+               .plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+                       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+                       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"
+                       "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+               .psize  = 50,
+               .digest = "\xd5\xca\x86\x2f\x4d\x21\xd5\xe6\x10\xe1"
+                         "\x8b\x4c\xf1\xbe\xb9\x7a\x43\x65\xec\xf4",
+       }, {
+               .key    = "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c",
+               .ksize  = 20,
+               .plaintext = "Test With Truncation",
+               .psize  = 20,
+               .digest = "\x76\x19\x69\x39\x78\xf9\x1d\x90\x53\x9a"
+                         "\xe7\x86\x50\x0f\xf3\xd8\xe0\x51\x8e\x39",
+       }, {
+               .key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa",
+               .ksize  = 80,
+               .plaintext = "Test Using Larger Than Block-Size Key - Hash Key First",
+               .psize  = 54,
+               .digest = "\x64\x66\xca\x07\xac\x5e\xac\x29\xe1\xbd"
+                         "\x52\x3e\x5a\xda\x76\x05\xb7\x91\xfd\x8b",
+       }, {
+               .key    = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+                       "\xaa\xaa",
+               .ksize  = 80,
+               .plaintext = "Test Using Larger Than Block-Size Key and Larger Than One "
+                          "Block-Size Data",
+               .psize  = 73,
+               .digest = "\x69\xea\x60\x79\x8d\x71\x61\x6c\xce\x5f"
+                         "\xd0\x87\x1e\x23\x75\x4c\xd7\x5d\x5a\x0a",
+       },
+};
+
 /*
  * HMAC-SHA1 test vectors from RFC2202
  */
@@ -1442,6 +1863,8 @@ static struct hash_testvec hmac_sha512_tv_template[] = {
 #define DES_CBC_DEC_TEST_VECTORS       4
 #define DES3_EDE_ENC_TEST_VECTORS      3
 #define DES3_EDE_DEC_TEST_VECTORS      3
+#define DES3_EDE_CBC_ENC_TEST_VECTORS  1
+#define DES3_EDE_CBC_DEC_TEST_VECTORS  1
 
 static struct cipher_testvec des_enc_tv_template[] = {
        { /* From Applied Cryptography */
@@ -1680,9 +2103,6 @@ static struct cipher_testvec des_cbc_dec_tv_template[] = {
        },
 };
 
-/*
- * We really need some more test vectors, especially for DES3 CBC.
- */
 static struct cipher_testvec des3_ede_enc_tv_template[] = {
        { /* These are from openssl */
                .key    = "\x01\x23\x45\x67\x89\xab\xcd\xef"
@@ -1745,6 +2165,94 @@ static struct cipher_testvec des3_ede_dec_tv_template[] = {
        },
 };
 
+static struct cipher_testvec des3_ede_cbc_enc_tv_template[] = {
+       { /* Generated from openssl */
+               .key    = "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24"
+                         "\x44\x4D\x99\x5A\x12\xD6\x40\xC0"
+                         "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8",
+               .klen   = 24,
+               .iv     = "\x7D\x33\x88\x93\x0F\x93\xB2\x42",
+               .input  = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e"
+                         "\x53\x20\x63\x65\x65\x72\x73\x74"
+                         "\x54\x20\x6f\x6f\x4d\x20\x6e\x61"
+                         "\x20\x79\x65\x53\x72\x63\x74\x65"
+                         "\x20\x73\x6f\x54\x20\x6f\x61\x4d"
+                         "\x79\x6e\x53\x20\x63\x65\x65\x72"
+                         "\x73\x74\x54\x20\x6f\x6f\x4d\x20"
+                         "\x6e\x61\x20\x79\x65\x53\x72\x63"
+                         "\x74\x65\x20\x73\x6f\x54\x20\x6f"
+                         "\x61\x4d\x79\x6e\x53\x20\x63\x65"
+                         "\x65\x72\x73\x74\x54\x20\x6f\x6f"
+                         "\x4d\x20\x6e\x61\x20\x79\x65\x53"
+                         "\x72\x63\x74\x65\x20\x73\x6f\x54"
+                         "\x20\x6f\x61\x4d\x79\x6e\x53\x20"
+                         "\x63\x65\x65\x72\x73\x74\x54\x20"
+                         "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
+               .ilen   = 128,
+               .result = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
+                         "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
+                         "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
+                         "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
+                         "\x90\x48\xfc\xf5\x8d\x29\x39\xcc"
+                         "\x8a\xd5\x35\x18\x36\x23\x4e\xd7"
+                         "\x76\xd1\xda\x0c\x94\x67\xbb\x04"
+                         "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea"
+                         "\x22\x64\x47\xaa\x8f\x75\x13\xbf"
+                         "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a"
+                         "\x71\x63\x2e\x89\x7b\x1e\x12\xca"
+                         "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a"
+                         "\xd6\xf9\x21\x31\x62\x44\x45\xa6"
+                         "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc"
+                         "\x9d\xde\xa5\x70\xe9\x42\x45\x8a"
+                         "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19",
+               .rlen   = 128,
+       },
+};
+
+static struct cipher_testvec des3_ede_cbc_dec_tv_template[] = {
+       { /* Generated from openssl */
+               .key    = "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24"
+                         "\x44\x4D\x99\x5A\x12\xD6\x40\xC0"
+                         "\xEA\xC2\x84\xE8\x14\x95\xDB\xE8",
+               .klen   = 24,
+               .iv     = "\x7D\x33\x88\x93\x0F\x93\xB2\x42",
+               .input  = "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
+                         "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
+                         "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
+                         "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
+                         "\x90\x48\xfc\xf5\x8d\x29\x39\xcc"
+                         "\x8a\xd5\x35\x18\x36\x23\x4e\xd7"
+                         "\x76\xd1\xda\x0c\x94\x67\xbb\x04"
+                         "\x8b\xf2\x03\x6c\xa8\xcf\xb6\xea"
+                         "\x22\x64\x47\xaa\x8f\x75\x13\xbf"
+                         "\x9f\xc2\xc3\xf0\xc9\x56\xc5\x7a"
+                         "\x71\x63\x2e\x89\x7b\x1e\x12\xca"
+                         "\xe2\x5f\xaf\xd8\xa4\xf8\xc9\x7a"
+                         "\xd6\xf9\x21\x31\x62\x44\x45\xa6"
+                         "\xd6\xbc\x5a\xd3\x2d\x54\x43\xcc"
+                         "\x9d\xde\xa5\x70\xe9\x42\x45\x8a"
+                         "\x6b\xfa\xb1\x91\x13\xb0\xd9\x19",
+               .ilen   = 128,
+               .result = "\x6f\x54\x20\x6f\x61\x4d\x79\x6e"
+                         "\x53\x20\x63\x65\x65\x72\x73\x74"
+                         "\x54\x20\x6f\x6f\x4d\x20\x6e\x61"
+                         "\x20\x79\x65\x53\x72\x63\x74\x65"
+                         "\x20\x73\x6f\x54\x20\x6f\x61\x4d"
+                         "\x79\x6e\x53\x20\x63\x65\x65\x72"
+                         "\x73\x74\x54\x20\x6f\x6f\x4d\x20"
+                         "\x6e\x61\x20\x79\x65\x53\x72\x63"
+                         "\x74\x65\x20\x73\x6f\x54\x20\x6f"
+                         "\x61\x4d\x79\x6e\x53\x20\x63\x65"
+                         "\x65\x72\x73\x74\x54\x20\x6f\x6f"
+                         "\x4d\x20\x6e\x61\x20\x79\x65\x53"
+                         "\x72\x63\x74\x65\x20\x73\x6f\x54"
+                         "\x20\x6f\x61\x4d\x79\x6e\x53\x20"
+                         "\x63\x65\x65\x72\x73\x74\x54\x20"
+                         "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
+               .rlen   = 128,
+       },
+};
+
 /*
  * Blowfish test vectors.
  */
index f65deda72d6102636e47554c9864d529df27a258..fda44679dffc72ebb05f3241e8780eb86cf56b97 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PCI)             += pci/
 obj-$(CONFIG_PARISC)           += parisc/
 obj-$(CONFIG_RAPIDIO)          += rapidio/
 obj-y                          += video/
+obj-y                          += gpu/
 obj-$(CONFIG_ACPI)             += acpi/
 # PnP must come after ACPI since it will eventually need to check if acpi
 # was used and do nothing if so
index c52fca833268c7f1eaf53c091fa2f41e49d5d4a0..bba867391a85bff4c08f9e61632026084cf59cea 100644 (file)
@@ -4,8 +4,6 @@
 
 menuconfig ACPI
        bool "ACPI (Advanced Configuration and Power Interface) Support"
-       depends on !X86_NUMAQ
-       depends on !X86_VISWS
        depends on !IA64_HP_SIM
        depends on IA64 || X86
        depends on PCI
index 57a43649a4616bf0cdaeb9614d8489e3dbbb9758..499ccc628d81f3f80326ecd1340cd1fea4463e79 100644 (file)
@@ -885,7 +885,8 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                /* set the min alignment and padding */
                blk_queue_update_dma_alignment(sdev->request_queue,
                                               ATA_DMA_PAD_SZ - 1);
-               blk_queue_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1);
+               blk_queue_update_dma_pad(sdev->request_queue,
+                                        ATA_DMA_PAD_SZ - 1);
 
                /* configure draining */
                buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
index 2b4b392dcbc1761339db874b4f9a02a5b49305c0..87a7f1d02578f194c821eb26049cbaafcf46a54c 100644 (file)
@@ -153,7 +153,7 @@ EXPORT_SYMBOL(set_trace_device);
  * it's not any guarantee, but it's a high _likelihood_ that
  * the match is valid).
  */
-void generate_resume_trace(void *tracedata, unsigned int user)
+void generate_resume_trace(const void *tracedata, unsigned int user)
 {
        unsigned short lineno = *(unsigned short *)tracedata;
        const char *file = *(const char **)(tracedata + 2);
index fdf4044d2e74a90a24ff7b5e44a16efcab52c7a4..1efe162e16d75a8a684557412d71ff32fbcb1595 100644 (file)
@@ -40,6 +40,7 @@ static ssize_t show_##name(struct sys_device *dev, char *buf) \
        return sprintf(buf, "%d\n", topology_##name(cpu));      \
 }
 
+#if defined(topology_thread_siblings) || defined(topology_core_siblings)
 static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf)
 {
        ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
@@ -54,21 +55,41 @@ static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf)
        }
        return n;
 }
+#endif
 
+#ifdef arch_provides_topology_pointers
 #define define_siblings_show_map(name)                                 \
-static inline ssize_t show_##name(struct sys_device *dev, char *buf)   \
+static ssize_t show_##name(struct sys_device *dev, char *buf)  \
 {                                                                      \
        unsigned int cpu = dev->id;                                     \
        return show_cpumap(0, &(topology_##name(cpu)), buf);            \
 }
 
 #define define_siblings_show_list(name)                                        \
-static inline ssize_t show_##name##_list(struct sys_device *dev, char *buf) \
+static ssize_t show_##name##_list(struct sys_device *dev, char *buf) \
 {                                                                      \
        unsigned int cpu = dev->id;                                     \
        return show_cpumap(1, &(topology_##name(cpu)), buf);            \
 }
 
+#else
+#define define_siblings_show_map(name)                                 \
+static ssize_t show_##name(struct sys_device *dev, char *buf)  \
+{                                                                      \
+       unsigned int cpu = dev->id;                                     \
+       cpumask_t mask = topology_##name(cpu);                          \
+       return show_cpumap(0, &mask, buf);                              \
+}
+
+#define define_siblings_show_list(name)                                        \
+static ssize_t show_##name##_list(struct sys_device *dev, char *buf) \
+{                                                                      \
+       unsigned int cpu = dev->id;                                     \
+       cpumask_t mask = topology_##name(cpu);                          \
+       return show_cpumap(1, &mask, buf);                              \
+}
+#endif
+
 #define define_siblings_show_func(name)                \
        define_siblings_show_map(name); define_siblings_show_list(name)
 
index cd03473f35474d743f7d2d4c2406443a215ce85a..a002a381df921f466b1293574aafb7a4b52e2b6b 100644 (file)
@@ -6628,15 +6628,18 @@ static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller)
  * DAC960_gam_ioctl is the ioctl function for performing RAID operations.
 */
 
-static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
-                           unsigned int Request, unsigned long Argument)
+static long DAC960_gam_ioctl(struct file *file, unsigned int Request,
+                                               unsigned long Argument)
 {
-  int ErrorCode = 0;
+  long ErrorCode = 0;
   if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+  lock_kernel();
   switch (Request)
     {
     case DAC960_IOCTL_GET_CONTROLLER_COUNT:
-      return DAC960_ControllerCount;
+      ErrorCode = DAC960_ControllerCount;
+      break;
     case DAC960_IOCTL_GET_CONTROLLER_INFO:
       {
        DAC960_ControllerInfo_T __user *UserSpaceControllerInfo =
@@ -6644,15 +6647,20 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        DAC960_ControllerInfo_T ControllerInfo;
        DAC960_Controller_T *Controller;
        int ControllerNumber;
-       if (UserSpaceControllerInfo == NULL) return -EINVAL;
-       ErrorCode = get_user(ControllerNumber,
+       if (UserSpaceControllerInfo == NULL)
+               ErrorCode = -EINVAL;
+       else ErrorCode = get_user(ControllerNumber,
                             &UserSpaceControllerInfo->ControllerNumber);
-       if (ErrorCode != 0) return ErrorCode;
+       if (ErrorCode != 0)
+               break;;
+       ErrorCode = -ENXIO;
        if (ControllerNumber < 0 ||
-           ControllerNumber > DAC960_ControllerCount - 1)
-         return -ENXIO;
+           ControllerNumber > DAC960_ControllerCount - 1) {
+         break;
+       }
        Controller = DAC960_Controllers[ControllerNumber];
-       if (Controller == NULL) return -ENXIO;
+       if (Controller == NULL)
+               break;;
        memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
        ControllerInfo.ControllerNumber = ControllerNumber;
        ControllerInfo.FirmwareType = Controller->FirmwareType;
@@ -6665,8 +6673,9 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        ControllerInfo.PCI_Address = Controller->PCI_Address;
        strcpy(ControllerInfo.ModelName, Controller->ModelName);
        strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
-       return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
+       ErrorCode = (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
                             sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
+       break;
       }
     case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
@@ -6684,30 +6693,39 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        int ControllerNumber, DataTransferLength;
        unsigned char *DataTransferBuffer = NULL;
        dma_addr_t DataTransferBufferDMA;
-       if (UserSpaceUserCommand == NULL) return -EINVAL;
+       if (UserSpaceUserCommand == NULL) {
+               ErrorCode = -EINVAL;
+               break;
+       }
        if (copy_from_user(&UserCommand, UserSpaceUserCommand,
                                   sizeof(DAC960_V1_UserCommand_T))) {
                ErrorCode = -EFAULT;
-               goto Failure1a;
+               break;
        }
        ControllerNumber = UserCommand.ControllerNumber;
+       ErrorCode = -ENXIO;
        if (ControllerNumber < 0 ||
            ControllerNumber > DAC960_ControllerCount - 1)
-         return -ENXIO;
+               break;
        Controller = DAC960_Controllers[ControllerNumber];
-       if (Controller == NULL) return -ENXIO;
-       if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL;
+       if (Controller == NULL)
+               break;
+       ErrorCode = -EINVAL;
+       if (Controller->FirmwareType != DAC960_V1_Controller)
+               break;
        CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode;
        DataTransferLength = UserCommand.DataTransferLength;
-       if (CommandOpcode & 0x80) return -EINVAL;
+       if (CommandOpcode & 0x80)
+               break;
        if (CommandOpcode == DAC960_V1_DCDB)
          {
            if (copy_from_user(&DCDB, UserCommand.DCDB,
                               sizeof(DAC960_V1_DCDB_T))) {
                ErrorCode = -EFAULT;
-               goto Failure1a;
+               break;
            }
-           if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL;
+           if (DCDB.Channel >= DAC960_V1_MaxChannels)
+                       break;
            if (!((DataTransferLength == 0 &&
                   DCDB.Direction
                   == DAC960_V1_DCDB_NoDataTransfer) ||
@@ -6717,38 +6735,37 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
                  (DataTransferLength < 0 &&
                   DCDB.Direction
                   == DAC960_V1_DCDB_DataTransferSystemToDevice)))
-             return -EINVAL;
+                       break;
            if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength)
                != abs(DataTransferLength))
-             return -EINVAL;
+                       break;
            DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice,
                        sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA);
-           if (DCDB_IOBUF == NULL)
-                       return -ENOMEM;
+           if (DCDB_IOBUF == NULL) {
+                       ErrorCode = -ENOMEM;
+                       break;
+               }
          }
+       ErrorCode = -ENOMEM;
        if (DataTransferLength > 0)
          {
            DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
                                DataTransferLength, &DataTransferBufferDMA);
-           if (DataTransferBuffer == NULL) {
-               ErrorCode = -ENOMEM;
-               goto Failure1;
-           }
+           if (DataTransferBuffer == NULL)
+               break;
            memset(DataTransferBuffer, 0, DataTransferLength);
          }
        else if (DataTransferLength < 0)
          {
            DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
                                -DataTransferLength, &DataTransferBufferDMA);
-           if (DataTransferBuffer == NULL) {
-               ErrorCode = -ENOMEM;
-               goto Failure1;
-           }
+           if (DataTransferBuffer == NULL)
+               break;
            if (copy_from_user(DataTransferBuffer,
                               UserCommand.DataTransferBuffer,
                               -DataTransferLength)) {
                ErrorCode = -EFAULT;
-               goto Failure1;
+               break;
            }
          }
        if (CommandOpcode == DAC960_V1_DCDB)
@@ -6825,8 +6842,7 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        if (DCDB_IOBUF != NULL)
          pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T),
                        DCDB_IOBUF, DCDB_IOBUFDMA);
-      Failure1a:
-       return ErrorCode;
+       break;
       }
     case DAC960_IOCTL_V2_EXECUTE_COMMAND:
       {
@@ -6844,32 +6860,43 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        dma_addr_t DataTransferBufferDMA;
        unsigned char *RequestSenseBuffer = NULL;
        dma_addr_t RequestSenseBufferDMA;
-       if (UserSpaceUserCommand == NULL) return -EINVAL;
+
+       ErrorCode = -EINVAL;
+       if (UserSpaceUserCommand == NULL)
+               break;
        if (copy_from_user(&UserCommand, UserSpaceUserCommand,
                           sizeof(DAC960_V2_UserCommand_T))) {
                ErrorCode = -EFAULT;
-               goto Failure2a;
+               break;
        }
+       ErrorCode = -ENXIO;
        ControllerNumber = UserCommand.ControllerNumber;
        if (ControllerNumber < 0 ||
            ControllerNumber > DAC960_ControllerCount - 1)
-         return -ENXIO;
+               break;
        Controller = DAC960_Controllers[ControllerNumber];
-       if (Controller == NULL) return -ENXIO;
-       if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+       if (Controller == NULL)
+               break;
+       if (Controller->FirmwareType != DAC960_V2_Controller){
+               ErrorCode = -EINVAL;
+               break;
+       }
        DataTransferLength = UserCommand.DataTransferLength;
+       ErrorCode = -ENOMEM;
        if (DataTransferLength > 0)
          {
            DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
                                DataTransferLength, &DataTransferBufferDMA);
-           if (DataTransferBuffer == NULL) return -ENOMEM;
+           if (DataTransferBuffer == NULL)
+               break;
            memset(DataTransferBuffer, 0, DataTransferLength);
          }
        else if (DataTransferLength < 0)
          {
            DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice,
                                -DataTransferLength, &DataTransferBufferDMA);
-           if (DataTransferBuffer == NULL) return -ENOMEM;
+           if (DataTransferBuffer == NULL)
+               break;
            if (copy_from_user(DataTransferBuffer,
                               UserCommand.DataTransferBuffer,
                               -DataTransferLength)) {
@@ -6979,8 +7006,7 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        if (RequestSenseBuffer != NULL)
          pci_free_consistent(Controller->PCIDevice, RequestSenseLength,
                RequestSenseBuffer, RequestSenseBufferDMA);
-      Failure2a:
-       return ErrorCode;
+        break;
       }
     case DAC960_IOCTL_V2_GET_HEALTH_STATUS:
       {
@@ -6990,21 +7016,33 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
        DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer;
        DAC960_Controller_T *Controller;
        int ControllerNumber;
-       if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
+       if (UserSpaceGetHealthStatus == NULL) {
+               ErrorCode = -EINVAL;
+               break;
+       }
        if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
-                          sizeof(DAC960_V2_GetHealthStatus_T)))
-               return -EFAULT;
+                          sizeof(DAC960_V2_GetHealthStatus_T))) {
+               ErrorCode = -EFAULT;
+               break;
+       }
+       ErrorCode = -ENXIO;
        ControllerNumber = GetHealthStatus.ControllerNumber;
        if (ControllerNumber < 0 ||
            ControllerNumber > DAC960_ControllerCount - 1)
-         return -ENXIO;
+                   break;
        Controller = DAC960_Controllers[ControllerNumber];
-       if (Controller == NULL) return -ENXIO;
-       if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+       if (Controller == NULL)
+               break;
+       if (Controller->FirmwareType != DAC960_V2_Controller) {
+               ErrorCode = -EINVAL;
+               break;
+       }
        if (copy_from_user(&HealthStatusBuffer,
                           GetHealthStatus.HealthStatusBuffer,
-                          sizeof(DAC960_V2_HealthStatusBuffer_T)))
-               return -EFAULT;
+                          sizeof(DAC960_V2_HealthStatusBuffer_T))) {
+               ErrorCode = -EFAULT;
+               break;
+       }
        while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
               == HealthStatusBuffer.StatusChangeCounter &&
               Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
@@ -7012,21 +7050,28 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
          {
            interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
                                           DAC960_MonitoringTimerInterval);
-           if (signal_pending(current)) return -EINTR;
+           if (signal_pending(current)) {
+               ErrorCode = -EINTR;
+               break;
+           }
          }
        if (copy_to_user(GetHealthStatus.HealthStatusBuffer,
                         Controller->V2.HealthStatusBuffer,
                         sizeof(DAC960_V2_HealthStatusBuffer_T)))
-               return -EFAULT;
-       return 0;
+               ErrorCode = -EFAULT;
+       else
+               ErrorCode =  0;
       }
+      default:
+       ErrorCode = -ENOTTY;
     }
-  return -EINVAL;
+  unlock_kernel();
+  return ErrorCode;
 }
 
 static const struct file_operations DAC960_gam_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = DAC960_gam_ioctl
+       .unlocked_ioctl = DAC960_gam_ioctl
 };
 
 static struct miscdevice DAC960_gam_dev = {
index 41f818be2f7ec8c4c737acaa16ecfeddc94f42b4..2f1746295d06fc438ac4b1ba923c2aeb1d634dd8 100644 (file)
@@ -1003,7 +1003,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
         * Enough people have their dip switches set backwards to
         * warrant a loud message for this special case.
         */
-       aoemajor = be16_to_cpu(get_unaligned(&h->major));
+       aoemajor = get_unaligned_be16(&h->major);
        if (aoemajor == 0xfff) {
                printk(KERN_ERR "aoe: Warning: shelf address is all ones.  "
                        "Check shelf dip switches.\n");
index 8b9549ab4a4e6eafd21b2e38b835618448cf31d9..27455ee1e9da555f680c7a694cf5874e9198a31b 100644 (file)
@@ -146,6 +146,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
 #include <linux/mtio.h>
 #include <linux/device.h>
 #include <linux/sched.h>       /* current, TASK_*, schedule_timeout() */
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -189,8 +190,7 @@ module_param_array(drive3, int, NULL, 0);
 #define ATAPI_LOG_SENSE                0x4d
 
 static int pt_open(struct inode *inode, struct file *file);
-static int pt_ioctl(struct inode *inode, struct file *file,
-                   unsigned int cmd, unsigned long arg);
+static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static int pt_release(struct inode *inode, struct file *file);
 static ssize_t pt_read(struct file *filp, char __user *buf,
                       size_t count, loff_t * ppos);
@@ -236,7 +236,7 @@ static const struct file_operations pt_fops = {
        .owner = THIS_MODULE,
        .read = pt_read,
        .write = pt_write,
-       .ioctl = pt_ioctl,
+       .unlocked_ioctl = pt_ioctl,
        .open = pt_open,
        .release = pt_release,
 };
@@ -685,8 +685,7 @@ out:
        return err;
 }
 
-static int pt_ioctl(struct inode *inode, struct file *file,
-        unsigned int cmd, unsigned long arg)
+static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct pt_unit *tape = file->private_data;
        struct mtop __user *p = (void __user *)arg;
@@ -700,23 +699,26 @@ static int pt_ioctl(struct inode *inode, struct file *file,
                switch (mtop.mt_op) {
 
                case MTREW:
+                       lock_kernel();
                        pt_rewind(tape);
+                       unlock_kernel();
                        return 0;
 
                case MTWEOF:
+                       lock_kernel();
                        pt_write_fm(tape);
+                       unlock_kernel();
                        return 0;
 
                default:
-                       printk("%s: Unimplemented mt_op %d\n", tape->name,
+                       /* FIXME: rate limit ?? */
+                       printk(KERN_DEBUG "%s: Unimplemented mt_op %d\n", tape->name,
                               mtop.mt_op);
                        return -EINVAL;
                }
 
        default:
-               printk("%s: Unimplemented ioctl 0x%x\n", tape->name, cmd);
-               return -EINVAL;
-
+               return -ENOTTY;
        }
 }
 
index 3ba1df93e9e32e8fb3c8641f7f11b9a33a575cc2..45bee918c46a821e5a5c4ec3c2a74ad96b8d8e72 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
+#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
 #include <linux/file.h>
@@ -2079,7 +2080,6 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd,
        unsigned char buf[64];
        int ret;
 
-       memset(buf, 0, sizeof(buf));
        init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.sense = &sense;
        cgc.buflen = pd->mode_offset + 12;
@@ -2126,7 +2126,6 @@ static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd,
        unsigned char *cap_buf;
        int ret, offset;
 
-       memset(buf, 0, sizeof(buf));
        cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset];
        init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN);
        cgc.sense = &sense;
@@ -2633,11 +2632,12 @@ end_io:
 
 
 
-static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec)
+static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
+                         struct bio_vec *bvec)
 {
        struct pktcdvd_device *pd = q->queuedata;
-       sector_t zone = ZONE(bio->bi_sector, pd);
-       int used = ((bio->bi_sector - zone) << 9) + bio->bi_size;
+       sector_t zone = ZONE(bmd->bi_sector, pd);
+       int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size;
        int remaining = (pd->settings.size << 9) - used;
        int remaining2;
 
@@ -2645,7 +2645,7 @@ static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_v
         * A bio <= PAGE_SIZE must be allowed. If it crosses a packet
         * boundary, pkt_make_request() will split the bio.
         */
-       remaining2 = PAGE_SIZE - bio->bi_size;
+       remaining2 = PAGE_SIZE - bmd->bi_size;
        remaining = max(remaining, remaining2);
 
        BUG_ON(remaining < 0);
@@ -2796,9 +2796,14 @@ out_mem:
        return ret;
 }
 
-static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct pktcdvd_device *pd;
+       long ret;
+
+       lock_kernel();
+       pd = inode->i_bdev->bd_disk->private_data;
 
        VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode));
 
@@ -2811,7 +2816,8 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
        case CDROM_LAST_WRITTEN:
        case CDROM_SEND_PACKET:
        case SCSI_IOCTL_SEND_COMMAND:
-               return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
+               ret = blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
+               break;
 
        case CDROMEJECT:
                /*
@@ -2820,14 +2826,15 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                 */
                if (pd->refcnt == 1)
                        pkt_lock_door(pd, 0);
-               return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
+               ret = blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
+               break;
 
        default:
                VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
-               return -ENOTTY;
+               ret = -ENOTTY;
        }
-
-       return 0;
+       unlock_kernel();
+       return ret;
 }
 
 static int pkt_media_changed(struct gendisk *disk)
@@ -2849,7 +2856,7 @@ static struct block_device_operations pktcdvd_ops = {
        .owner =                THIS_MODULE,
        .open =                 pkt_open,
        .release =              pkt_close,
-       .ioctl =                pkt_ioctl,
+       .unlocked_ioctl =       pkt_ioctl,
        .media_changed =        pkt_media_changed,
 };
 
@@ -3014,7 +3021,8 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
        mutex_unlock(&ctl_mutex);
 }
 
-static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long pkt_ctl_ioctl(struct file *file, unsigned int cmd,
+                                               unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
        struct pkt_ctrl_command ctrl_cmd;
@@ -3031,16 +3039,22 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
        case PKT_CTRL_CMD_SETUP:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
+               lock_kernel();
                ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev);
                ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev);
+               unlock_kernel();
                break;
        case PKT_CTRL_CMD_TEARDOWN:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
+               lock_kernel();
                ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
+               unlock_kernel();
                break;
        case PKT_CTRL_CMD_STATUS:
+               lock_kernel();
                pkt_get_status(&ctrl_cmd);
+               unlock_kernel();
                break;
        default:
                return -ENOTTY;
@@ -3053,7 +3067,7 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
 
 
 static const struct file_operations pkt_ctl_fops = {
-       .ioctl   = pkt_ctl_ioctl,
+       .unlocked_ioctl  = pkt_ctl_ioctl,
        .owner   = THIS_MODULE,
 };
 
index f2fff5799ddf0fe1b41909b64d606d747f9081f7..9ae05c5842344c56d06a187764dbd328ab5e4822 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/cdrom.h>
 #include <linux/module.h>
 
 #include <xen/xenbus.h>
@@ -153,6 +154,40 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
        return 0;
 }
 
+int blkif_ioctl(struct inode *inode, struct file *filep,
+               unsigned command, unsigned long argument)
+{
+       struct blkfront_info *info =
+               inode->i_bdev->bd_disk->private_data;
+       int i;
+
+       dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n",
+               command, (long)argument);
+
+       switch (command) {
+       case CDROMMULTISESSION:
+               dev_dbg(&info->xbdev->dev, "FIXME: support multisession CDs later\n");
+               for (i = 0; i < sizeof(struct cdrom_multisession); i++)
+                       if (put_user(0, (char __user *)(argument + i)))
+                               return -EFAULT;
+               return 0;
+
+       case CDROM_GET_CAPABILITY: {
+               struct gendisk *gd = info->gd;
+               if (gd->flags & GENHD_FL_CD)
+                       return 0;
+               return -EINVAL;
+       }
+
+       default:
+               /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
+                 command);*/
+               return -EINVAL; /* same return as native Linux */
+       }
+
+       return 0;
+}
+
 /*
  * blkif_queue_request
  *
@@ -324,6 +359,9 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
        /* Make sure buffer addresses are sector-aligned. */
        blk_queue_dma_alignment(rq, 511);
 
+       /* Make sure we don't use bounce buffers. */
+       blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
+
        gd->queue = rq;
 
        return 0;
@@ -546,7 +584,7 @@ static int setup_blkring(struct xenbus_device *dev,
 
        info->ring_ref = GRANT_INVALID_REF;
 
-       sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+       sring = (struct blkif_sring *)__get_free_page(GFP_NOIO | __GFP_HIGH);
        if (!sring) {
                xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
                return -ENOMEM;
@@ -703,7 +741,8 @@ static int blkif_recover(struct blkfront_info *info)
        int j;
 
        /* Stage 1: Make a safe copy of the shadow state. */
-       copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+       copy = kmalloc(sizeof(info->shadow),
+                      GFP_NOIO | __GFP_REPEAT | __GFP_HIGH);
        if (!copy)
                return -ENOMEM;
        memcpy(copy, info->shadow, sizeof(info->shadow));
@@ -959,7 +998,7 @@ static int blkif_release(struct inode *inode, struct file *filep)
                struct xenbus_device *dev = info->xbdev;
                enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
 
-               if (state == XenbusStateClosing)
+               if (state == XenbusStateClosing && info->is_ready)
                        blkfront_closing(dev);
        }
        return 0;
@@ -971,6 +1010,7 @@ static struct block_device_operations xlvbd_block_fops =
        .open = blkif_open,
        .release = blkif_release,
        .getgeo = blkif_getgeo,
+       .ioctl = blkif_ioctl,
 };
 
 
@@ -1006,7 +1046,7 @@ static int __init xlblk_init(void)
 module_init(xlblk_init);
 
 
-static void xlblk_exit(void)
+static void __exit xlblk_exit(void)
 {
        return xenbus_unregister_driver(&blkfront);
 }
index 69f26eb6415bdbb9824ed89ca1307134fe55b647..a5da356326515c637f7a66ff04c1cd018c828f31 100644 (file)
@@ -461,37 +461,27 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi,
                          struct media_event_desc *med)
 {
        struct packet_command cgc;
-       unsigned char *buffer;
-       struct event_header *eh;
-       int ret = 1;
-
-       buffer = kmalloc(8, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
+       unsigned char buffer[8];
+       struct event_header *eh = (struct event_header *) buffer;
 
-       eh = (struct event_header *)buffer;
-
-       init_cdrom_command(&cgc, buffer, 8, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
        cgc.cmd[1] = 1;         /* IMMED */
        cgc.cmd[4] = 1 << 4;    /* media event */
-       cgc.cmd[8] = 8;
+       cgc.cmd[8] = sizeof(buffer);
        cgc.quiet = 1;
 
        if (cdi->ops->generic_packet(cdi, &cgc))
-               goto err;
+               return 1;
 
        if (be16_to_cpu(eh->data_len) < sizeof(*med))
-               goto err;
+               return 1;
 
        if (eh->nea || eh->notification_class != 0x4)
-               goto err;
+               return 1;
 
-       memcpy(med, buffer + sizeof(*eh), sizeof(*med));
-       ret = 0;
-err:
-       kfree(buffer);
-       return ret;
+       memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
+       return 0;
 }
 
 /*
@@ -501,82 +491,68 @@ err:
 static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char *buffer;
-       int ret = 1;
-
-       buffer = kmalloc(16, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
+       char buffer[16];
 
-       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
        cgc.timeout = HZ;
        cgc.quiet = 1;
 
        if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) {
                cdi->mrw_mode_page = MRW_MODE_PC;
-               ret = 0;
+               return 0;
        } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) {
                cdi->mrw_mode_page = MRW_MODE_PC_PRE1;
-               ret = 0;
+               return 0;
        }
-       kfree(buffer);
-       return ret;
+
+       return 1;
 }
 
 static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write)
 {
        struct packet_command cgc;
        struct mrw_feature_desc *mfd;
-       unsigned char *buffer;
+       unsigned char buffer[16];
        int ret;
 
        *write = 0;
-       buffer = kmalloc(16, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
 
-       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[3] = CDF_MRW;
-       cgc.cmd[8] = 16;
+       cgc.cmd[8] = sizeof(buffer);
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];
-       if (be16_to_cpu(mfd->feature_code) != CDF_MRW) {
-               ret = 1;
-               goto err;
-       }
+       if (be16_to_cpu(mfd->feature_code) != CDF_MRW)
+               return 1;
        *write = mfd->write;
 
        if ((ret = cdrom_mrw_probe_pc(cdi))) {
                *write = 0;
+               return ret;
        }
-err:
-       kfree(buffer);
-       return ret;
+
+       return 0;
 }
 
 static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont)
 {
        struct packet_command cgc;
-       unsigned char *buffer;
+       unsigned char buffer[12];
        int ret;
 
        printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : "");
 
-       buffer = kmalloc(12, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
        /*
         * FmtData bit set (bit 4), format type is 1
         */
-       init_cdrom_command(&cgc, buffer, 12, CGC_DATA_WRITE);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE);
        cgc.cmd[0] = GPCMD_FORMAT_UNIT;
        cgc.cmd[1] = (1 << 4) | 1;
 
@@ -603,7 +579,6 @@ static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont)
        if (ret)
                printk(KERN_INFO "cdrom: bgformat failed\n");
 
-       kfree(buffer);
        return ret;
 }
 
@@ -663,17 +638,16 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
 {
        struct packet_command cgc;
        struct mode_page_header *mph;
-       char *buffer;
+       char buffer[16];
        int ret, offset, size;
 
-       buffer = kmalloc(16, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
-       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
+       cgc.buffer = buffer;
+       cgc.buflen = sizeof(buffer);
 
        if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0)))
-               goto err;
+               return ret;
 
        mph = (struct mode_page_header *) buffer;
        offset = be16_to_cpu(mph->desc_length);
@@ -683,70 +657,55 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
        cgc.buflen = size;
 
        if ((ret = cdrom_mode_select(cdi, &cgc)))
-               goto err;
+               return ret;
 
        printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]);
-       ret = 0;
-err:
-       kfree(buffer);
-       return ret;
+       return 0;
 }
 
 static int cdrom_get_random_writable(struct cdrom_device_info *cdi,
                              struct rwrt_feature_desc *rfd)
 {
        struct packet_command cgc;
-       char *buffer;
+       char buffer[24];
        int ret;
 
-       buffer = kmalloc(24, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       init_cdrom_command(&cgc, buffer, 24, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;   /* often 0x46 */
        cgc.cmd[3] = CDF_RWRT;                  /* often 0x0020 */
-       cgc.cmd[8] = 24;                        /* often 0x18 */
+       cgc.cmd[8] = sizeof(buffer);            /* often 0x18 */
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd));
-       ret = 0;
-err:
-       kfree(buffer);
-       return ret;
+       return 0;
 }
 
 static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char *buffer;
+       char buffer[16];
        __be16 *feature_code;
        int ret;
 
-       buffer = kmalloc(16, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[3] = CDF_HWDM;
-       cgc.cmd[8] = 16;
+       cgc.cmd[8] = sizeof(buffer);
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        feature_code = (__be16 *) &buffer[sizeof(struct feature_header)];
        if (be16_to_cpu(*feature_code) == CDF_HWDM)
-               ret = 0;
-err:
-       kfree(buffer);
-       return ret;
+               return 0;
+
+       return 1;
 }
 
 
@@ -837,14 +796,10 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi)
 static int mo_open_write(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char *buffer;
+       char buffer[255];
        int ret;
 
-       buffer = kmalloc(255, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       init_cdrom_command(&cgc, buffer, 4, CGC_DATA_READ);
+       init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ);
        cgc.quiet = 1;
 
        /*
@@ -861,15 +816,10 @@ static int mo_open_write(struct cdrom_device_info *cdi)
        }
 
        /* drive gave us no info, let the user go ahead */
-       if (ret) {
-               ret = 0;
-               goto err;
-       }
+       if (ret)
+               return 0;
 
-       ret = buffer[3] & 0x80;
-err:
-       kfree(buffer);
-       return ret;
+       return buffer[3] & 0x80;
 }
 
 static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
@@ -892,19 +842,15 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
 static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char *buffer;
+       char buffer[32];
        int ret, mmc3_profile;
 
-       buffer = kmalloc(32, GFP_KERNEL);
-       if (!buffer)
-               return;
-
-       init_cdrom_command(&cgc, buffer, 32, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[1] = 0;
        cgc.cmd[2] = cgc.cmd[3] = 0;            /* Starting Feature Number */
-       cgc.cmd[8] = 32;                        /* Allocation Length */
+       cgc.cmd[8] = sizeof(buffer);            /* Allocation Length */
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
@@ -913,7 +859,6 @@ static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
                mmc3_profile = (buffer[6] << 8) | buffer[7];
 
        cdi->mmc3_profile = mmc3_profile;
-       kfree(buffer);
 }
 
 static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
@@ -1628,15 +1573,12 @@ static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned t
 static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 {
        int ret;
-       u_char *buf;
+       u_char buf[20];
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
-       rpc_state_t *rpc_state;
-
-       buf = kzalloc(20, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
+       rpc_state_t rpc_state;
 
+       memset(buf, 0, sizeof(buf));
        init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ);
 
        switch (ai->type) {
@@ -1647,7 +1589,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsa.agid, 0);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
                ai->lsa.agid = buf[7] >> 6;
                /* Returning data, let host change state */
@@ -1658,7 +1600,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsk.agid, 2);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
                copy_key(ai->lsk.key, &buf[4]);
                /* Returning data, let host change state */
@@ -1669,7 +1611,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsc.agid, 1);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
                copy_chal(ai->lsc.chal, &buf[4]);
                /* Returning data, let host change state */
@@ -1686,7 +1628,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                cgc.cmd[2] = ai->lstk.lba >> 24;
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
                ai->lstk.cpm = (buf[4] >> 7) & 1;
                ai->lstk.cp_sec = (buf[4] >> 6) & 1;
@@ -1700,7 +1642,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsasf.agid, 5);
                
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
                ai->lsasf.asf = buf[7] & 1;
                break;
@@ -1713,7 +1655,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                copy_chal(&buf[4], ai->hsc.chal);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
                ai->type = DVD_LU_SEND_KEY1;
                break;
@@ -1726,7 +1668,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
                if ((ret = cdo->generic_packet(cdi, &cgc))) {
                        ai->type = DVD_AUTH_FAILURE;
-                       goto err;
+                       return ret;
                }
                ai->type = DVD_AUTH_ESTABLISHED;
                break;
@@ -1737,23 +1679,24 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); 
                setup_report_key(&cgc, ai->lsa.agid, 0x3f);
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
                break;
 
        /* Get region settings */
        case DVD_LU_SEND_RPC_STATE:
                cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
                setup_report_key(&cgc, 0, 8);
+               memset(&rpc_state, 0, sizeof(rpc_state_t));
+               cgc.buffer = (char *) &rpc_state;
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
 
-               rpc_state = (rpc_state_t *)buf;
-               ai->lrpcs.type = rpc_state->type_code;
-               ai->lrpcs.vra = rpc_state->vra;
-               ai->lrpcs.ucca = rpc_state->ucca;
-               ai->lrpcs.region_mask = rpc_state->region_mask;
-               ai->lrpcs.rpc_scheme = rpc_state->rpc_scheme;
+               ai->lrpcs.type = rpc_state.type_code;
+               ai->lrpcs.vra = rpc_state.vra;
+               ai->lrpcs.ucca = rpc_state.ucca;
+               ai->lrpcs.region_mask = rpc_state.region_mask;
+               ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
                break;
 
        /* Set region settings */
@@ -1764,23 +1707,20 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                buf[4] = ai->hrpcs.pdrc;
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       goto err;
+                       return ret;
                break;
 
        default:
                cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
-               ret = -ENOTTY;
-               goto err;
+               return -ENOTTY;
        }
-       ret = 0;
-err:
-       kfree(buf);
-       return ret;
+
+       return 0;
 }
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-       unsigned char *buf, *base;
+       unsigned char buf[21], *base;
        struct dvd_layer *layer;
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
@@ -1789,11 +1729,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        if (layer_num >= DVD_LAYERS)
                return -EINVAL;
 
-       buf = kmalloc(21, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       init_cdrom_command(&cgc, buf, 21, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[6] = layer_num;
        cgc.cmd[7] = s->type;
@@ -1805,7 +1741,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        cgc.quiet = 1;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        base = &buf[4];
        layer = &s->physical.layer[layer_num];
@@ -1829,24 +1765,17 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
        layer->bca = base[16] >> 7;
 
-       ret = 0;
-err:
-       kfree(buf);
-       return ret;
+       return 0;
 }
 
 static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
 {
        int ret;
-       u_char *buf;
+       u_char buf[8];
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       buf = kmalloc(8, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       init_cdrom_command(&cgc, buf, 8, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[6] = s->copyright.layer_num;
        cgc.cmd[7] = s->type;
@@ -1854,15 +1783,12 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
        cgc.cmd[9] = cgc.buflen & 0xff;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        s->copyright.cpst = buf[4];
        s->copyright.rmi = buf[5];
 
-       ret = 0;
-err:
-       kfree(buf);
-       return ret;
+       return 0;
 }
 
 static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
@@ -1894,33 +1820,26 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
 static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
 {
        int ret;
-       u_char *buf;
+       u_char buf[4 + 188];
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       buf = kmalloc(4 + 188, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       init_cdrom_command(&cgc, buf, 4 + 188, CGC_DATA_READ);
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[7] = s->type;
        cgc.cmd[9] = cgc.buflen & 0xff;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        s->bca.len = buf[0] << 8 | buf[1];
        if (s->bca.len < 12 || s->bca.len > 188) {
                cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len);
-               ret = -EIO;
-               goto err;
+               return -EIO;
        }
        memcpy(s->bca.value, &buf[4], s->bca.len);
-       ret = 0;
-err:
-       kfree(buf);
-       return ret;
+
+       return 0;
 }
 
 static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
@@ -2020,13 +1939,9 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
-       char *buffer;
+       char buffer[32];
        int ret;
 
-       buffer = kmalloc(32, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
        init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
        cgc.cmd[1] = 2;     /* MSF addressing */
@@ -2035,7 +1950,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
        cgc.cmd[8] = 16;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               goto err;
+               return ret;
 
        subchnl->cdsc_audiostatus = cgc.buffer[1];
        subchnl->cdsc_format = CDROM_MSF;
@@ -2050,10 +1965,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
        subchnl->cdsc_absaddr.msf.second = cgc.buffer[10];
        subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11];
 
-       ret = 0;
-err:
-       kfree(buffer);
-       return ret;
+       return 0;
 }
 
 /*
index 4c1c584e9eb678d366e575a3cd983b287d4419e0..81630a68475cd7ad8859c650c20a6431fae60539 100644 (file)
@@ -101,7 +101,6 @@ obj-$(CONFIG_TELCLOCK)              += tlclk.o
 
 obj-$(CONFIG_MWAVE)            += mwave/
 obj-$(CONFIG_AGP)              += agp/
-obj-$(CONFIG_DRM)              += drm/
 obj-$(CONFIG_PCMCIA)           += pcmcia/
 obj-$(CONFIG_IPMI_HANDLER)     += ipmi/
 
index 13665db363d6df4025fe43c074f98c189d54a76c..481ffe87c716472548d99c7d79bde85872bb0c0e 100644 (file)
 #include <asm/page.h>          /* PAGE_SIZE */
 #include <asm/e820.h>
 #include <asm/k8.h>
+#include <asm/gart.h>
 #include "agp.h"
 
-/* PTE bits. */
-#define GPTE_VALID     1
-#define GPTE_COHERENT  2
-
-/* Aperture control register bits. */
-#define GARTEN         (1<<0)
-#define DISGARTCPU     (1<<4)
-#define DISGARTIO      (1<<5)
-
-/* GART cache control register bits. */
-#define INVGART                (1<<0)
-#define GARTPTEERR     (1<<1)
-
-/* K8 On-cpu GART registers */
-#define AMD64_GARTAPERTURECTL  0x90
-#define AMD64_GARTAPERTUREBASE 0x94
-#define AMD64_GARTTABLEBASE    0x98
-#define AMD64_GARTCACHECTL     0x9c
-#define AMD64_GARTEN           (1<<0)
-
 /* NVIDIA K8 registers */
 #define NVIDIA_X86_64_0_APBASE         0x10
 #define NVIDIA_X86_64_1_APBASE1                0x50
@@ -165,29 +146,18 @@ static int amd64_fetch_size(void)
  * In a multiprocessor x86-64 system, this function gets
  * called once for each CPU.
  */
-static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table)
+static u64 amd64_configure(struct pci_dev *hammer, u64 gatt_table)
 {
        u64 aperturebase;
        u32 tmp;
-       u64 addr, aper_base;
+       u64 aper_base;
 
        /* Address to map to */
-       pci_read_config_dword (hammer, AMD64_GARTAPERTUREBASE, &tmp);
+       pci_read_config_dword(hammer, AMD64_GARTAPERTUREBASE, &tmp);
        aperturebase = tmp << 25;
        aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK);
 
-       /* address of the mappings table */
-       addr = (u64) gatt_table;
-       addr >>= 12;
-       tmp = (u32) addr<<4;
-       tmp &= ~0xf;
-       pci_write_config_dword (hammer, AMD64_GARTTABLEBASE, tmp);
-
-       /* Enable GART translation for this hammer. */
-       pci_read_config_dword(hammer, AMD64_GARTAPERTURECTL, &tmp);
-       tmp |= GARTEN;
-       tmp &= ~(DISGARTCPU | DISGARTIO);
-       pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp);
+       enable_gart_translation(hammer, gatt_table);
 
        return aper_base;
 }
@@ -226,9 +196,9 @@ static void amd64_cleanup(void)
         for (i = 0; i < num_k8_northbridges; i++) {
                struct pci_dev *dev = k8_northbridges[i];
                /* disable gart translation */
-               pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp);
+               pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp);
                tmp &= ~AMD64_GARTEN;
-               pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp);
+               pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp);
        }
 }
 
@@ -258,24 +228,10 @@ static const struct agp_bridge_driver amd_8151_driver = {
 };
 
 /* Some basic sanity checks for the aperture. */
-static int __devinit aperture_valid(u64 aper, u32 size)
+static int __devinit agp_aperture_valid(u64 aper, u32 size)
 {
-       if (aper == 0) {
-               printk(KERN_ERR PFX "No aperture\n");
-               return 0;
-       }
-       if (size < 32*1024*1024) {
-               printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20);
-               return 0;
-       }
-       if ((u64)aper + size > 0x100000000ULL) {
-               printk(KERN_ERR PFX "Aperture out of bounds\n");
+       if (!aperture_valid(aper, size, 32*1024*1024))
                return 0;
-       }
-       if (e820_any_mapped(aper, aper + size, E820_RAM)) {
-               printk(KERN_ERR PFX "Aperture pointing to RAM\n");
-               return 0;
-       }
 
        /* Request the Aperture. This catches cases when someone else
           already put a mapping in there - happens with some very broken BIOS
@@ -308,11 +264,11 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
        u32 nb_order, nb_base;
        u16 apsize;
 
-       pci_read_config_dword(nb, 0x90, &nb_order);
+       pci_read_config_dword(nb, AMD64_GARTAPERTURECTL, &nb_order);
        nb_order = (nb_order >> 1) & 7;
-       pci_read_config_dword(nb, 0x94, &nb_base);
+       pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base);
        nb_aper = nb_base << 25;
-       if (aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) {
+       if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) {
                return 0;
        }
 
@@ -331,12 +287,23 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
        pci_read_config_dword(agp, 0x10, &aper_low);
        pci_read_config_dword(agp, 0x14, &aper_hi);
        aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
+
+       /*
+        * On some sick chips APSIZE is 0. This means it wants 4G
+        * so let double check that order, and lets trust the AMD NB settings
+        */
+       if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) {
+               printk(KERN_INFO "Aperture size %u MB is not right, using settings from NB\n",
+                                 32 << order);
+               order = nb_order;
+       }
+
        printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order);
-       if (order < 0 || !aperture_valid(aper, (32*1024*1024)<<order))
+       if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order))
                return -1;
 
-       pci_write_config_dword(nb, 0x90, order << 1);
-       pci_write_config_dword(nb, 0x94, aper >> 25);
+       pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1);
+       pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25);
 
        return 0;
 }
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
deleted file mode 100644 (file)
index 1283ded..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Makefile for the drm device driver.  This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
-               drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
-               drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
-               drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
-               drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
-
-tdfx-objs   := tdfx_drv.o
-r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
-mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
-i810-objs   := i810_drv.o i810_dma.o
-i830-objs   := i830_drv.o i830_dma.o i830_irq.o
-i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
-radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
-sis-objs    := sis_drv.o sis_mm.o
-savage-objs := savage_drv.o savage_bci.o savage_state.o
-via-objs    := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
-
-ifeq ($(CONFIG_COMPAT),y)
-drm-objs    += drm_ioc32.o
-radeon-objs += radeon_ioc32.o
-mga-objs    += mga_ioc32.o
-r128-objs   += r128_ioc32.o
-i915-objs   += i915_ioc32.o
-endif
-
-obj-$(CONFIG_DRM)      += drm.o
-obj-$(CONFIG_DRM_TDFX) += tdfx.o
-obj-$(CONFIG_DRM_R128) += r128.o
-obj-$(CONFIG_DRM_RADEON)+= radeon.o
-obj-$(CONFIG_DRM_MGA)  += mga.o
-obj-$(CONFIG_DRM_I810) += i810.o
-obj-$(CONFIG_DRM_I830) += i830.o
-obj-$(CONFIG_DRM_I915)  += i915.o
-obj-$(CONFIG_DRM_SIS)   += sis.o
-obj-$(CONFIG_DRM_SAVAGE)+= savage.o
-obj-$(CONFIG_DRM_VIA)  +=via.o
index dd68f8541c2dc4f13c26943607b8574e379bbbc8..db2ae4216279377e7cc092a63ff2e5c0e6db691b 100644 (file)
@@ -39,9 +39,14 @@ static int xencons_irq;
 
 /* ------------------------------------------------------------------ */
 
+static unsigned long console_pfn = ~0ul;
+
 static inline struct xencons_interface *xencons_interface(void)
 {
-       return mfn_to_virt(xen_start_info->console.domU.mfn);
+       if (console_pfn == ~0ul)
+               return mfn_to_virt(xen_start_info->console.domU.mfn);
+       else
+               return __va(console_pfn << PAGE_SHIFT);
 }
 
 static inline void notify_daemon(void)
@@ -101,20 +106,32 @@ static int __init xen_init(void)
 {
        struct hvc_struct *hp;
 
-       if (!is_running_on_xen())
-               return 0;
+       if (!is_running_on_xen() ||
+           is_initial_xendomain() ||
+           !xen_start_info->console.domU.evtchn)
+               return -ENODEV;
 
        xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
        if (xencons_irq < 0)
-               xencons_irq = 0 /* NO_IRQ */;
+               xencons_irq = 0; /* NO_IRQ */
+
        hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
        if (IS_ERR(hp))
                return PTR_ERR(hp);
 
        hvc = hp;
+
+       console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn);
+
        return 0;
 }
 
+void xen_console_resume(void)
+{
+       if (xencons_irq)
+               rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq);
+}
+
 static void __exit xen_fini(void)
 {
        if (hvc)
@@ -134,12 +151,28 @@ module_init(xen_init);
 module_exit(xen_fini);
 console_initcall(xen_cons_init);
 
+static void raw_console_write(const char *str, int len)
+{
+       while(len > 0) {
+               int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
+               if (rc <= 0)
+                       break;
+
+               str += rc;
+               len -= rc;
+       }
+}
+
+#ifdef CONFIG_EARLY_PRINTK
 static void xenboot_write_console(struct console *console, const char *string,
                                  unsigned len)
 {
        unsigned int linelen, off = 0;
        const char *pos;
 
+       raw_console_write(string, len);
+
+       write_console(0, "(early) ", 8);
        while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
                linelen = pos-string+off;
                if (off + linelen > len)
@@ -155,5 +188,23 @@ static void xenboot_write_console(struct console *console, const char *string,
 struct console xenboot_console = {
        .name           = "xenboot",
        .write          = xenboot_write_console,
-       .flags          = CON_PRINTBUFFER | CON_BOOT,
+       .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
 };
+#endif /* CONFIG_EARLY_PRINTK */
+
+void xen_raw_console_write(const char *str)
+{
+       raw_console_write(str, strlen(str));
+}
+
+void xen_raw_printk(const char *fmt, ...)
+{
+       static char buf[512];
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       xen_raw_console_write(buf);
+}
index 4a933d4134231cd095a859f286a0d8c7e08e434e..59ca35156d8159699f960cdd1aac43a448dc023f 100644 (file)
@@ -32,8 +32,9 @@
 #include <linux/fs.h>
 #include <linux/delay.h>
 #include <linux/bitrev.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/smp_lock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -1405,11 +1406,11 @@ static void stop_monitor(struct cm4000_dev *dev)
        DEBUGP(3, dev, "<- stop_monitor\n");
 }
 
-static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-                    unsigned long arg)
+static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct cm4000_dev *dev = filp->private_data;
        unsigned int iobase = dev->p_dev->io.BasePort1;
+       struct inode *inode = filp->f_path.dentry->d_inode;
        struct pcmcia_device *link;
        int size;
        int rc;
@@ -1426,38 +1427,42 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode),
               iminor(inode), ioctl_names[_IOC_NR(cmd)]);
 
+       lock_kernel();
+       rc = -ENODEV;
        link = dev_table[iminor(inode)];
        if (!pcmcia_dev_present(link)) {
                DEBUGP(4, dev, "DEV_OK false\n");
-               return -ENODEV;
+               goto out;
        }
 
        if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
                DEBUGP(4, dev, "CMM_ABSENT flag set\n");
-               return -ENODEV;
+               goto out;
        }
+       rc = EINVAL;
 
        if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) {
                DEBUGP(4, dev, "ioctype mismatch\n");
-               return -EINVAL;
+               goto out;
        }
        if (_IOC_NR(cmd) > CM_IOC_MAXNR) {
                DEBUGP(4, dev, "iocnr mismatch\n");
-               return -EINVAL;
+               goto out;
        }
        size = _IOC_SIZE(cmd);
-       rc = 0;
+       rc = -EFAULT;
        DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n",
              _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd);
 
        if (_IOC_DIR(cmd) & _IOC_READ) {
                if (!access_ok(VERIFY_WRITE, argp, size))
-                       return -EFAULT;
+                       goto out;
        }
        if (_IOC_DIR(cmd) & _IOC_WRITE) {
                if (!access_ok(VERIFY_READ, argp, size))
-                       return -EFAULT;
+                       goto out;
        }
+       rc = 0;
 
        switch (cmd) {
        case CM_IOCGSTATUS:
@@ -1477,9 +1482,9 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        if (test_bit(IS_BAD_CARD, &dev->flags))
                                status |= CM_BAD_CARD;
                        if (copy_to_user(argp, &status, sizeof(int)))
-                               return -EFAULT;
+                               rc = -EFAULT;
                }
-               return 0;
+               break;
        case CM_IOCGATR:
                DEBUGP(4, dev, "... in CM_IOCGATR\n");
                {
@@ -1492,25 +1497,29 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                              || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
                                  != 0)))) {
                                if (filp->f_flags & O_NONBLOCK)
-                                       return -EAGAIN;
-                               return -ERESTARTSYS;
+                                       rc = -EAGAIN;
+                               else
+                                       rc = -ERESTARTSYS;
+                               break;
                        }
 
+                       rc = -EFAULT;
                        if (test_bit(IS_ATR_VALID, &dev->flags) == 0) {
                                tmp = -1;
                                if (copy_to_user(&(atreq->atr_len), &tmp,
                                                 sizeof(int)))
-                                       return -EFAULT;
+                                       break;
                        } else {
                                if (copy_to_user(atreq->atr, dev->atr,
                                                 dev->atr_len))
-                                       return -EFAULT;
+                                       break;
 
                                tmp = dev->atr_len;
                                if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int)))
-                                       return -EFAULT;
+                                       break;
                        }
-                       return 0;
+                       rc = 0;
+                       break;
                }
        case CM_IOCARDOFF:
 
@@ -1538,8 +1547,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                              || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
                                  == 0)))) {
                                if (filp->f_flags & O_NONBLOCK)
-                                       return -EAGAIN;
-                               return -ERESTARTSYS;
+                                       rc = -EAGAIN;
+                               else
+                                       rc = -ERESTARTSYS;
+                               break;
                        }
                        /* Set Flags0 = 0x42 */
                        DEBUGP(4, dev, "Set Flags0=0x42 \n");
@@ -1554,8 +1565,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                              || (test_bit(IS_ATR_VALID, (void *)&dev->flags) !=
                                  0)))) {
                                if (filp->f_flags & O_NONBLOCK)
-                                       return -EAGAIN;
-                               return -ERESTARTSYS;
+                                       rc = -EAGAIN;
+                               else
+                                       rc = -ERESTARTSYS;
+                               break;
                        }
                }
                /* release lock */
@@ -1568,8 +1581,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        struct ptsreq krnptsreq;
 
                        if (copy_from_user(&krnptsreq, argp,
-                                          sizeof(struct ptsreq)))
-                               return -EFAULT;
+                                          sizeof(struct ptsreq))) {
+                               rc = -EFAULT;
+                               break;
+                       }
 
                        rc = 0;
                        DEBUGP(4, dev, "... in CM_IOCSPTS\n");
@@ -1580,8 +1595,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                              || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
                                  != 0)))) {
                                if (filp->f_flags & O_NONBLOCK)
-                                       return -EAGAIN;
-                               return -ERESTARTSYS;
+                                       rc = -EAGAIN;
+                               else
+                                       rc = -ERESTARTSYS;
+                               break;
                        }
                        /* get IO lock */
                        if (wait_event_interruptible
@@ -1590,8 +1607,10 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                              || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
                                  == 0)))) {
                                if (filp->f_flags & O_NONBLOCK)
-                                       return -EAGAIN;
-                               return -ERESTARTSYS;
+                                       rc = -EAGAIN;
+                               else
+                                       rc = -ERESTARTSYS;
+                               break;
                        }
 
                        if ((rc = set_protocol(dev, &krnptsreq)) != 0) {
@@ -1604,7 +1623,7 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                        wake_up_interruptible(&dev->ioq);
 
                }
-               return rc;
+               break;
 #ifdef PCMCIA_DEBUG
        case CM_IOSDBGLVL:      /* set debug log level */
                {
@@ -1612,18 +1631,20 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 
                        old_pc_debug = pc_debug;
                        if (copy_from_user(&pc_debug, argp, sizeof(int)))
-                               return -EFAULT;
-
-                       if (old_pc_debug != pc_debug)
+                               rc = -EFAULT;
+                       else if (old_pc_debug != pc_debug)
                                DEBUGP(0, dev, "Changed debug log level "
                                       "to %i\n", pc_debug);
                }
-               return rc;
+               break;
 #endif
        default:
                DEBUGP(4, dev, "... in default (unknown IOCTL code)\n");
-               return -EINVAL;
+               rc = -ENOTTY;
        }
+out:
+       unlock_kernel();
+       return rc;
 }
 
 static int cmm_open(struct inode *inode, struct file *filp)
@@ -1631,16 +1652,22 @@ static int cmm_open(struct inode *inode, struct file *filp)
        struct cm4000_dev *dev;
        struct pcmcia_device *link;
        int minor = iminor(inode);
+       int ret;
 
        if (minor >= CM4000_MAX_DEV)
                return -ENODEV;
 
+       lock_kernel();
        link = dev_table[minor];
-       if (link == NULL || !pcmcia_dev_present(link))
-               return -ENODEV;
+       if (link == NULL || !pcmcia_dev_present(link)) {
+               ret = -ENODEV;
+               goto out;
+       }
 
-       if (link->open)
-               return -EBUSY;
+       if (link->open) {
+               ret = -EBUSY;
+               goto out;
+       }
 
        dev = link->priv;
        filp->private_data = dev;
@@ -1660,8 +1687,10 @@ static int cmm_open(struct inode *inode, struct file *filp)
         * vaild = block until valid (or card
         * inserted)
         */
-       if (filp->f_flags & O_NONBLOCK)
-               return -EAGAIN;
+       if (filp->f_flags & O_NONBLOCK) {
+               ret = -EAGAIN;
+               goto out;
+       }
 
        dev->mdelay = T_50MSEC;
 
@@ -1671,7 +1700,10 @@ static int cmm_open(struct inode *inode, struct file *filp)
        link->open = 1;         /* only one open per device */
 
        DEBUGP(2, dev, "<- cmm_open\n");
-       return nonseekable_open(inode, filp);
+       ret = nonseekable_open(inode, filp);
+out:
+       unlock_kernel();
+       return ret;
 }
 
 static int cmm_close(struct inode *inode, struct file *filp)
@@ -1897,7 +1929,7 @@ static const struct file_operations cm4000_fops = {
        .owner  = THIS_MODULE,
        .read   = cmm_read,
        .write  = cmm_write,
-       .ioctl  = cmm_ioctl,
+       .unlocked_ioctl = cmm_ioctl,
        .open   = cmm_open,
        .release= cmm_close,
 };
index 035084c07329cd87bfa42da3a70e6fe624b3c201..6181f8a9b0bd0309cb4670dd0d572af91fc8689f 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/fs.h>
 #include <linux/delay.h>
 #include <linux/poll.h>
+#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -448,23 +449,30 @@ static int cm4040_open(struct inode *inode, struct file *filp)
        struct reader_dev *dev;
        struct pcmcia_device *link;
        int minor = iminor(inode);
+       int ret;
 
        if (minor >= CM_MAX_DEV)
                return -ENODEV;
 
+       lock_kernel();
        link = dev_table[minor];
-       if (link == NULL || !pcmcia_dev_present(link))
-               return -ENODEV;
+       if (link == NULL || !pcmcia_dev_present(link)) {
+               ret = -ENODEV;
+               goto out;
+       }
 
-       if (link->open)
-               return -EBUSY;
+       if (link->open) {
+               ret = -EBUSY;
+               goto out;
+       }
 
        dev = link->priv;
        filp->private_data = dev;
 
        if (filp->f_flags & O_NONBLOCK) {
                DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
-               return -EAGAIN;
+               ret = -EAGAIN;
+               goto out;
        }
 
        link->open = 1;
@@ -473,7 +481,10 @@ static int cm4040_open(struct inode *inode, struct file *filp)
        mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
 
        DEBUGP(2, dev, "<- cm4040_open (successfully)\n");
-       return nonseekable_open(inode, filp);
+       ret = nonseekable_open(inode, filp);
+out:
+       unlock_kernel();
+       return ret;
 }
 
 static int cm4040_close(struct inode *inode, struct file *filp)
index 00c7f8407e3ecfcfaf3520e0dbdc99ec4ac7933c..cc7dcea2d2830599d05c955589456c14cf9aa37b 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/device_id.h>
 #include <pcmcia/ss.h>
index 43b71b69daa57be26972fe50f0c6213596e7a847..e522144cba3af9bc9d9e5e9bbc1e5dcb05e693c0 100644 (file)
@@ -174,4 +174,30 @@ config CRYPTO_DEV_HIFN_795X_RNG
          Select this option if you want to enable the random number generator
          on the HIFN 795x crypto adapters.
 
+config CRYPTO_DEV_TALITOS
+       tristate "Talitos Freescale Security Engine (SEC)"
+       select CRYPTO_ALGAPI
+       select CRYPTO_AUTHENC
+       select HW_RANDOM
+       depends on FSL_SOC
+       help
+         Say 'Y' here to use the Freescale Security Engine (SEC)
+         to offload cryptographic algorithm computation.
+
+         The Freescale SEC is present on PowerQUICC 'E' processors, such
+         as the MPC8349E and MPC8548E.
+
+         To compile this driver as a module, choose M here: the module
+         will be called talitos.
+
+config CRYPTO_DEV_IXP4XX
+       tristate "Driver for IXP4xx crypto hardware acceleration"
+       depends on ARCH_IXP4XX
+       select CRYPTO_DES
+       select CRYPTO_ALGAPI
+       select CRYPTO_AUTHENC
+       select CRYPTO_BLKCIPHER
+       help
+         Driver for the IXP4xx NPE crypto engine.
+
 endif # CRYPTO_HW
index c0327f0dadc56e878df6679575dba3b10ff60f43..73557b2968d33710ae4c0a5745d6ac4bce0dedef 100644 (file)
@@ -2,3 +2,5 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
+obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
+obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
index 81f3f950cd7d4c5007a64cadd11c18b61c8c6db2..4d22b21bd3e30ad872adaef9b87cd003904832bd 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 #include <linux/highmem.h>
-#include <linux/interrupt.h>
 #include <linux/crypto.h>
 #include <linux/hw_random.h>
 #include <linux/ktime.h>
@@ -369,7 +368,9 @@ static atomic_t hifn_dev_number;
 #define        HIFN_D_DST_RSIZE                80*4
 #define        HIFN_D_RES_RSIZE                24*4
 
-#define HIFN_QUEUE_LENGTH              HIFN_D_CMD_RSIZE-5
+#define HIFN_D_DST_DALIGN              4
+
+#define HIFN_QUEUE_LENGTH              HIFN_D_CMD_RSIZE-1
 
 #define AES_MIN_KEY_SIZE               16
 #define AES_MAX_KEY_SIZE               32
@@ -535,10 +536,10 @@ struct hifn_crypt_command
  */
 struct hifn_mac_command
 {
-       volatile u16            masks;
-       volatile u16            header_skip;
-       volatile u16            source_count;
-       volatile u16            reserved;
+       volatile __le16         masks;
+       volatile __le16         header_skip;
+       volatile __le16         source_count;
+       volatile __le16         reserved;
 };
 
 #define        HIFN_MAC_CMD_ALG_MASK           0x0001
@@ -564,10 +565,10 @@ struct hifn_mac_command
 
 struct hifn_comp_command
 {
-       volatile u16            masks;
-       volatile u16            header_skip;
-       volatile u16            source_count;
-       volatile u16            reserved;
+       volatile __le16         masks;
+       volatile __le16         header_skip;
+       volatile __le16         source_count;
+       volatile __le16         reserved;
 };
 
 #define        HIFN_COMP_CMD_SRCLEN_M          0xc000
@@ -583,10 +584,10 @@ struct hifn_comp_command
 
 struct hifn_base_result
 {
-       volatile u16            flags;
-       volatile u16            session;
-       volatile u16            src_cnt;                /* 15:0 of source count */
-       volatile u16            dst_cnt;                /* 15:0 of dest count */
+       volatile __le16         flags;
+       volatile __le16         session;
+       volatile __le16         src_cnt;                /* 15:0 of source count */
+       volatile __le16         dst_cnt;                /* 15:0 of dest count */
 };
 
 #define        HIFN_BASE_RES_DSTOVERRUN        0x0200  /* destination overrun */
@@ -597,8 +598,8 @@ struct hifn_base_result
 
 struct hifn_comp_result
 {
-       volatile u16            flags;
-       volatile u16            crc;
+       volatile __le16         flags;
+       volatile __le16         crc;
 };
 
 #define        HIFN_COMP_RES_LCB_M             0xff00  /* longitudinal check byte */
@@ -609,8 +610,8 @@ struct hifn_comp_result
 
 struct hifn_mac_result
 {
-       volatile u16            flags;
-       volatile u16            reserved;
+       volatile __le16         flags;
+       volatile __le16         reserved;
        /* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */
 };
 
@@ -619,8 +620,8 @@ struct hifn_mac_result
 
 struct hifn_crypt_result
 {
-       volatile u16            flags;
-       volatile u16            reserved;
+       volatile __le16         flags;
+       volatile __le16         reserved;
 };
 
 #define        HIFN_CRYPT_RES_SRC_NOTZERO      0x0001  /* source expired */
@@ -686,12 +687,12 @@ static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg)
 
 static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
 {
-       writel(val, dev->bar[0] + reg);
+       writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg);
 }
 
 static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
 {
-       writel(val, dev->bar[1] + reg);
+       writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg);
 }
 
 static void hifn_wait_puc(struct hifn_device *dev)
@@ -894,7 +895,7 @@ static int hifn_enable_crypto(struct hifn_device *dev)
        char *offtbl = NULL;
        int i;
 
-       for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) {
+       for (i = 0; i < ARRAY_SIZE(pci2id); i++) {
                if (pci2id[i].pci_vendor == dev->pdev->vendor &&
                                pci2id[i].pci_prod == dev->pdev->device) {
                        offtbl = pci2id[i].card_id;
@@ -1037,14 +1038,14 @@ static void hifn_init_registers(struct hifn_device *dev)
        hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
 
        /* write all 4 ring address registers */
-       hifn_write_1(dev, HIFN_1_DMA_CRAR, __cpu_to_le32(dptr +
-                               offsetof(struct hifn_dma, cmdr[0])));
-       hifn_write_1(dev, HIFN_1_DMA_SRAR, __cpu_to_le32(dptr +
-                               offsetof(struct hifn_dma, srcr[0])));
-       hifn_write_1(dev, HIFN_1_DMA_DRAR, __cpu_to_le32(dptr +
-                               offsetof(struct hifn_dma, dstr[0])));
-       hifn_write_1(dev, HIFN_1_DMA_RRAR, __cpu_to_le32(dptr +
-                               offsetof(struct hifn_dma, resr[0])));
+       hifn_write_1(dev, HIFN_1_DMA_CRAR, dptr +
+                               offsetof(struct hifn_dma, cmdr[0]));
+       hifn_write_1(dev, HIFN_1_DMA_SRAR, dptr +
+                               offsetof(struct hifn_dma, srcr[0]));
+       hifn_write_1(dev, HIFN_1_DMA_DRAR, dptr +
+                               offsetof(struct hifn_dma, dstr[0]));
+       hifn_write_1(dev, HIFN_1_DMA_RRAR, dptr +
+                               offsetof(struct hifn_dma, resr[0]));
 
        mdelay(2);
 #if 0
@@ -1166,109 +1167,15 @@ static int hifn_setup_crypto_command(struct hifn_device *dev,
        return cmd_len;
 }
 
-static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
-               unsigned int offset, unsigned int size)
-{
-       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
-       int idx;
-       dma_addr_t addr;
-
-       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE);
-
-       idx = dma->srci;
-
-       dma->srcr[idx].p = __cpu_to_le32(addr);
-       dma->srcr[idx].l = __cpu_to_le32(size) | HIFN_D_VALID |
-                       HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST;
-
-       if (++idx == HIFN_D_SRC_RSIZE) {
-               dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID |
-                               HIFN_D_JUMP |
-                               HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
-               idx = 0;
-       }
-
-       dma->srci = idx;
-       dma->srcu++;
-
-       if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) {
-               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
-               dev->flags |= HIFN_FLAG_SRC_BUSY;
-       }
-
-       return size;
-}
-
-static void hifn_setup_res_desc(struct hifn_device *dev)
-{
-       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
-
-       dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT |
-                       HIFN_D_VALID | HIFN_D_LAST);
-       /*
-        * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID |
-        *                                      HIFN_D_LAST | HIFN_D_NOINVALID);
-        */
-
-       if (++dma->resi == HIFN_D_RES_RSIZE) {
-               dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID |
-                               HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
-               dma->resi = 0;
-       }
-
-       dma->resu++;
-
-       if (!(dev->flags & HIFN_FLAG_RES_BUSY)) {
-               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
-               dev->flags |= HIFN_FLAG_RES_BUSY;
-       }
-}
-
-static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
-               unsigned offset, unsigned size)
-{
-       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
-       int idx;
-       dma_addr_t addr;
-
-       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE);
-
-       idx = dma->dsti;
-       dma->dstr[idx].p = __cpu_to_le32(addr);
-       dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID |
-                       HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST);
-
-       if (++idx == HIFN_D_DST_RSIZE) {
-               dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID |
-                               HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
-                               HIFN_D_LAST | HIFN_D_NOINVALID);
-               idx = 0;
-       }
-       dma->dsti = idx;
-       dma->dstu++;
-
-       if (!(dev->flags & HIFN_FLAG_DST_BUSY)) {
-               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
-               dev->flags |= HIFN_FLAG_DST_BUSY;
-       }
-}
-
-static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff,
-               struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv,
-               struct hifn_context *ctx)
+static int hifn_setup_cmd_desc(struct hifn_device *dev,
+               struct hifn_context *ctx, void *priv, unsigned int nbytes)
 {
        struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
        int cmd_len, sa_idx;
        u8 *buf, *buf_pos;
        u16 mask;
 
-       dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n",
-                       dev->name, spage, soff, dpage, doff, nbytes, priv, ctx);
-
-       sa_idx = dma->resi;
-
-       hifn_setup_src_desc(dev, spage, soff, nbytes);
-
+       sa_idx = dma->cmdi;
        buf_pos = buf = dma->command_bufs[dma->cmdi];
 
        mask = 0;
@@ -1370,16 +1277,113 @@ static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned
                hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA);
                dev->flags |= HIFN_FLAG_CMD_BUSY;
        }
-
-       hifn_setup_dst_desc(dev, dpage, doff, nbytes);
-       hifn_setup_res_desc(dev);
-
        return 0;
 
 err_out:
        return -EINVAL;
 }
 
+static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
+               unsigned int offset, unsigned int size)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int idx;
+       dma_addr_t addr;
+
+       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE);
+
+       idx = dma->srci;
+
+       dma->srcr[idx].p = __cpu_to_le32(addr);
+       dma->srcr[idx].l = __cpu_to_le32(size | HIFN_D_VALID |
+                       HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+
+       if (++idx == HIFN_D_SRC_RSIZE) {
+               dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+                               HIFN_D_JUMP |
+                               HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+               idx = 0;
+       }
+
+       dma->srci = idx;
+       dma->srcu++;
+
+       if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_SRC_BUSY;
+       }
+
+       return size;
+}
+
+static void hifn_setup_res_desc(struct hifn_device *dev)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+       dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT |
+                       HIFN_D_VALID | HIFN_D_LAST);
+       /*
+        * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID |
+        *                                      HIFN_D_LAST);
+        */
+
+       if (++dma->resi == HIFN_D_RES_RSIZE) {
+               dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID |
+                               HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+               dma->resi = 0;
+       }
+
+       dma->resu++;
+
+       if (!(dev->flags & HIFN_FLAG_RES_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_RES_BUSY;
+       }
+}
+
+static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
+               unsigned offset, unsigned size)
+{
+       struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+       int idx;
+       dma_addr_t addr;
+
+       addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE);
+
+       idx = dma->dsti;
+       dma->dstr[idx].p = __cpu_to_le32(addr);
+       dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID |
+                       HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+
+       if (++idx == HIFN_D_DST_RSIZE) {
+               dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+                               HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
+                               HIFN_D_LAST);
+               idx = 0;
+       }
+       dma->dsti = idx;
+       dma->dstu++;
+
+       if (!(dev->flags & HIFN_FLAG_DST_BUSY)) {
+               hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
+               dev->flags |= HIFN_FLAG_DST_BUSY;
+       }
+}
+
+static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff,
+               struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv,
+               struct hifn_context *ctx)
+{
+       dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n",
+                       dev->name, spage, soff, dpage, doff, nbytes, priv, ctx);
+
+       hifn_setup_src_desc(dev, spage, soff, nbytes);
+       hifn_setup_cmd_desc(dev, ctx, priv, nbytes);
+       hifn_setup_dst_desc(dev, dpage, doff, nbytes);
+       hifn_setup_res_desc(dev);
+       return 0;
+}
+
 static int ablkcipher_walk_init(struct ablkcipher_walk *w,
                int num, gfp_t gfp_flags)
 {
@@ -1431,7 +1435,7 @@ static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist
                return -EINVAL;
 
        while (size) {
-               copy = min(drest, src->length);
+               copy = min(drest, min(size, src->length));
 
                saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1);
                memcpy(daddr, saddr + src->offset, copy);
@@ -1458,10 +1462,6 @@ static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist
 static int ablkcipher_walk(struct ablkcipher_request *req,
                struct ablkcipher_walk *w)
 {
-       unsigned blocksize =
-               crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
-       unsigned alignmask =
-               crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
        struct scatterlist *src, *dst, *t;
        void *daddr;
        unsigned int nbytes = req->nbytes, offset, copy, diff;
@@ -1477,16 +1477,14 @@ static int ablkcipher_walk(struct ablkcipher_request *req,
                dst = &req->dst[idx];
 
                dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, "
-                               "blocksize: %u, nbytes: %u.\n",
+                               "nbytes: %u.\n",
                                __func__, src->length, dst->length, src->offset,
-                               dst->offset, offset, blocksize, nbytes);
-
-               if (src->length & (blocksize - 1) ||
-                               src->offset & (alignmask - 1) ||
-                               dst->length & (blocksize - 1) ||
-                               dst->offset & (alignmask - 1) ||
-                               offset) {
-                       unsigned slen = src->length - offset;
+                               dst->offset, offset, nbytes);
+
+               if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) ||
+                   !IS_ALIGNED(dst->length, HIFN_D_DST_DALIGN) ||
+                   offset) {
+                       unsigned slen = min(src->length - offset, nbytes);
                        unsigned dlen = PAGE_SIZE;
 
                        t = &w->cache[idx];
@@ -1498,8 +1496,8 @@ static int ablkcipher_walk(struct ablkcipher_request *req,
 
                        idx += err;
 
-                       copy = slen & ~(blocksize - 1);
-                       diff = slen & (blocksize - 1);
+                       copy = slen & ~(HIFN_D_DST_DALIGN - 1);
+                       diff = slen & (HIFN_D_DST_DALIGN - 1);
 
                        if (dlen < nbytes) {
                                /*
@@ -1507,7 +1505,7 @@ static int ablkcipher_walk(struct ablkcipher_request *req,
                                 * to put there additional blocksized chunk,
                                 * so we mark that page as containing only
                                 * blocksize aligned chunks:
-                                *      t->length = (slen & ~(blocksize - 1));
+                                *      t->length = (slen & ~(HIFN_D_DST_DALIGN - 1));
                                 * and increase number of bytes to be processed
                                 * in next chunk:
                                 *      nbytes += diff;
@@ -1544,7 +1542,7 @@ static int ablkcipher_walk(struct ablkcipher_request *req,
 
                        kunmap_atomic(daddr, KM_SOFTIRQ0);
                } else {
-                       nbytes -= src->length;
+                       nbytes -= min(src->length, nbytes);
                        idx++;
                }
 
@@ -1563,14 +1561,10 @@ static int hifn_setup_session(struct ablkcipher_request *req)
        struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
        struct hifn_device *dev = ctx->dev;
        struct page *spage, *dpage;
-       unsigned long soff, doff, flags;
+       unsigned long soff, doff, dlen, flags;
        unsigned int nbytes = req->nbytes, idx = 0, len;
        int err = -EINVAL, sg_num;
        struct scatterlist *src, *dst, *t;
-       unsigned blocksize =
-               crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
-       unsigned alignmask =
-               crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
 
        if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB)
                goto err_out_exit;
@@ -1578,17 +1572,14 @@ static int hifn_setup_session(struct ablkcipher_request *req)
        ctx->walk.flags = 0;
 
        while (nbytes) {
-               src = &req->src[idx];
                dst = &req->dst[idx];
+               dlen = min(dst->length, nbytes);
 
-               if (src->length & (blocksize - 1) ||
-                               src->offset & (alignmask - 1) ||
-                               dst->length & (blocksize - 1) ||
-                               dst->offset & (alignmask - 1)) {
+               if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) ||
+                   !IS_ALIGNED(dlen, HIFN_D_DST_DALIGN))
                        ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED;
-               }
 
-               nbytes -= src->length;
+               nbytes -= dlen;
                idx++;
        }
 
@@ -1602,7 +1593,10 @@ static int hifn_setup_session(struct ablkcipher_request *req)
        idx = 0;
 
        sg_num = ablkcipher_walk(req, &ctx->walk);
-
+       if (sg_num < 0) {
+               err = sg_num;
+               goto err_out_exit;
+       }
        atomic_set(&ctx->sg_num, sg_num);
 
        spin_lock_irqsave(&dev->lock, flags);
@@ -1640,7 +1634,7 @@ static int hifn_setup_session(struct ablkcipher_request *req)
                if (err)
                        goto err_out;
 
-               nbytes -= len;
+               nbytes -= min(len, nbytes);
        }
 
        dev->active = HIFN_DEFAULT_ACTIVE_NUM;
@@ -1651,7 +1645,7 @@ static int hifn_setup_session(struct ablkcipher_request *req)
 err_out:
        spin_unlock_irqrestore(&dev->lock, flags);
 err_out_exit:
-       if (err && printk_ratelimit())
+       if (err)
                dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
                                "type: %u, err: %d.\n",
                        dev->name, ctx->iv, ctx->ivsize,
@@ -1745,8 +1739,7 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset
                return -EINVAL;
 
        while (size) {
-
-               copy = min(dst->length, srest);
+               copy = min(srest, min(dst->length, size));
 
                daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
                memcpy(daddr + dst->offset + offset, saddr, copy);
@@ -1803,7 +1796,7 @@ static void hifn_process_ready(struct ablkcipher_request *req, int error)
                                        sg_page(dst), dst->length, nbytes);
 
                                if (!t->length) {
-                                       nbytes -= dst->length;
+                                       nbytes -= min(dst->length, nbytes);
                                        idx++;
                                        continue;
                                }
@@ -2202,9 +2195,9 @@ static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op,
                return err;
 
        if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen)
-               err = hifn_process_queue(dev);
+               hifn_process_queue(dev);
 
-       return err;
+       return -EINPROGRESS;
 }
 
 /*
@@ -2364,7 +2357,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
         * 3DES ECB, CBC, CFB and OFB modes.
         */
        {
-               .name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .name = "cfb(des3_ede)", .drv_name = "cfb-3des", .bsize = 8,
                .ablkcipher = {
                        .min_keysize    =       HIFN_3DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_3DES_KEY_LENGTH,
@@ -2374,7 +2367,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .name = "ofb(des3_ede)", .drv_name = "ofb-3des", .bsize = 8,
                .ablkcipher = {
                        .min_keysize    =       HIFN_3DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_3DES_KEY_LENGTH,
@@ -2384,8 +2377,9 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .name = "cbc(des3_ede)", .drv_name = "cbc-3des", .bsize = 8,
                .ablkcipher = {
+                       .ivsize         =       HIFN_IV_LENGTH,
                        .min_keysize    =       HIFN_3DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_3DES_KEY_LENGTH,
                        .setkey         =       hifn_setkey,
@@ -2394,7 +2388,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+               .name = "ecb(des3_ede)", .drv_name = "ecb-3des", .bsize = 8,
                .ablkcipher = {
                        .min_keysize    =       HIFN_3DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_3DES_KEY_LENGTH,
@@ -2408,7 +2402,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
         * DES ECB, CBC, CFB and OFB modes.
         */
        {
-               .name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8,
+               .name = "cfb(des)", .drv_name = "cfb-des", .bsize = 8,
                .ablkcipher = {
                        .min_keysize    =       HIFN_DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_DES_KEY_LENGTH,
@@ -2418,7 +2412,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8,
+               .name = "ofb(des)", .drv_name = "ofb-des", .bsize = 8,
                .ablkcipher = {
                        .min_keysize    =       HIFN_DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_DES_KEY_LENGTH,
@@ -2428,8 +2422,9 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8,
+               .name = "cbc(des)", .drv_name = "cbc-des", .bsize = 8,
                .ablkcipher = {
+                       .ivsize         =       HIFN_IV_LENGTH,
                        .min_keysize    =       HIFN_DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_DES_KEY_LENGTH,
                        .setkey         =       hifn_setkey,
@@ -2438,7 +2433,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8,
+               .name = "ecb(des)", .drv_name = "ecb-des", .bsize = 8,
                .ablkcipher = {
                        .min_keysize    =       HIFN_DES_KEY_LENGTH,
                        .max_keysize    =       HIFN_DES_KEY_LENGTH,
@@ -2452,7 +2447,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
         * AES ECB, CBC, CFB and OFB modes.
         */
        {
-               .name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .name = "ecb(aes)", .drv_name = "ecb-aes", .bsize = 16,
                .ablkcipher = {
                        .min_keysize    =       AES_MIN_KEY_SIZE,
                        .max_keysize    =       AES_MAX_KEY_SIZE,
@@ -2462,8 +2457,9 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .name = "cbc(aes)", .drv_name = "cbc-aes", .bsize = 16,
                .ablkcipher = {
+                       .ivsize         =       HIFN_AES_IV_LENGTH,
                        .min_keysize    =       AES_MIN_KEY_SIZE,
                        .max_keysize    =       AES_MAX_KEY_SIZE,
                        .setkey         =       hifn_setkey,
@@ -2472,7 +2468,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .name = "cfb(aes)", .drv_name = "cfb-aes", .bsize = 16,
                .ablkcipher = {
                        .min_keysize    =       AES_MIN_KEY_SIZE,
                        .max_keysize    =       AES_MAX_KEY_SIZE,
@@ -2482,7 +2478,7 @@ static struct hifn_alg_template hifn_alg_templates[] = {
                },
        },
        {
-               .name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+               .name = "ofb(aes)", .drv_name = "ofb-aes", .bsize = 16,
                .ablkcipher = {
                        .min_keysize    =       AES_MIN_KEY_SIZE,
                        .max_keysize    =       AES_MAX_KEY_SIZE,
@@ -2514,15 +2510,14 @@ static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
                return -ENOMEM;
 
        snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name);
-       snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name);
+       snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-%s",
+                t->drv_name, dev->name);
 
        alg->alg.cra_priority = 300;
        alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
        alg->alg.cra_blocksize = t->bsize;
        alg->alg.cra_ctxsize = sizeof(struct hifn_context);
-       alg->alg.cra_alignmask = 15;
-       if (t->bsize == 8)
-               alg->alg.cra_alignmask = 3;
+       alg->alg.cra_alignmask = 0;
        alg->alg.cra_type = &crypto_ablkcipher_type;
        alg->alg.cra_module = THIS_MODULE;
        alg->alg.cra_u.ablkcipher = t->ablkcipher;
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
new file mode 100644 (file)
index 0000000..42a107f
--- /dev/null
@@ -0,0 +1,1506 @@
+/*
+ * Intel IXP4xx NPE-C crypto driver
+ *
+ * Copyright (C) 2008 Christian Hohnstaedt <chohnstaedt@innominate.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/crypto.h>
+#include <linux/kernel.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <crypto/ctr.h>
+#include <crypto/des.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
+
+#include <asm/arch/npe.h>
+#include <asm/arch/qmgr.h>
+
+#define MAX_KEYLEN 32
+
+/* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */
+#define NPE_CTX_LEN 80
+#define AES_BLOCK128 16
+
+#define NPE_OP_HASH_VERIFY   0x01
+#define NPE_OP_CCM_ENABLE    0x04
+#define NPE_OP_CRYPT_ENABLE  0x08
+#define NPE_OP_HASH_ENABLE   0x10
+#define NPE_OP_NOT_IN_PLACE  0x20
+#define NPE_OP_HMAC_DISABLE  0x40
+#define NPE_OP_CRYPT_ENCRYPT 0x80
+
+#define NPE_OP_CCM_GEN_MIC   0xcc
+#define NPE_OP_HASH_GEN_ICV  0x50
+#define NPE_OP_ENC_GEN_KEY   0xc9
+
+#define MOD_ECB     0x0000
+#define MOD_CTR     0x1000
+#define MOD_CBC_ENC 0x2000
+#define MOD_CBC_DEC 0x3000
+#define MOD_CCM_ENC 0x4000
+#define MOD_CCM_DEC 0x5000
+
+#define KEYLEN_128  4
+#define KEYLEN_192  6
+#define KEYLEN_256  8
+
+#define CIPH_DECR   0x0000
+#define CIPH_ENCR   0x0400
+
+#define MOD_DES     0x0000
+#define MOD_TDEA2   0x0100
+#define MOD_3DES   0x0200
+#define MOD_AES     0x0800
+#define MOD_AES128  (0x0800 | KEYLEN_128)
+#define MOD_AES192  (0x0900 | KEYLEN_192)
+#define MOD_AES256  (0x0a00 | KEYLEN_256)
+
+#define MAX_IVLEN   16
+#define NPE_ID      2  /* NPE C */
+#define NPE_QLEN    16
+/* Space for registering when the first
+ * NPE_QLEN crypt_ctl are busy */
+#define NPE_QLEN_TOTAL 64
+
+#define SEND_QID    29
+#define RECV_QID    30
+
+#define CTL_FLAG_UNUSED                0x0000
+#define CTL_FLAG_USED          0x1000
+#define CTL_FLAG_PERFORM_ABLK  0x0001
+#define CTL_FLAG_GEN_ICV       0x0002
+#define CTL_FLAG_GEN_REVAES    0x0004
+#define CTL_FLAG_PERFORM_AEAD  0x0008
+#define CTL_FLAG_MASK          0x000f
+
+#define HMAC_IPAD_VALUE   0x36
+#define HMAC_OPAD_VALUE   0x5C
+#define HMAC_PAD_BLOCKLEN SHA1_BLOCK_SIZE
+
+#define MD5_DIGEST_SIZE   16
+
+struct buffer_desc {
+       u32 phys_next;
+       u16 buf_len;
+       u16 pkt_len;
+       u32 phys_addr;
+       u32 __reserved[4];
+       struct buffer_desc *next;
+};
+
+struct crypt_ctl {
+       u8 mode;                /* NPE_OP_*  operation mode */
+       u8 init_len;
+       u16 reserved;
+       u8 iv[MAX_IVLEN];       /* IV for CBC mode or CTR IV for CTR mode */
+       u32 icv_rev_aes;        /* icv or rev aes */
+       u32 src_buf;
+       u32 dst_buf;
+       u16 auth_offs;          /* Authentication start offset */
+       u16 auth_len;           /* Authentication data length */
+       u16 crypt_offs;         /* Cryption start offset */
+       u16 crypt_len;          /* Cryption data length */
+       u32 aadAddr;            /* Additional Auth Data Addr for CCM mode */
+       u32 crypto_ctx;         /* NPE Crypto Param structure address */
+
+       /* Used by Host: 4*4 bytes*/
+       unsigned ctl_flags;
+       union {
+               struct ablkcipher_request *ablk_req;
+               struct aead_request *aead_req;
+               struct crypto_tfm *tfm;
+       } data;
+       struct buffer_desc *regist_buf;
+       u8 *regist_ptr;
+};
+
+struct ablk_ctx {
+       struct buffer_desc *src;
+       struct buffer_desc *dst;
+       unsigned src_nents;
+       unsigned dst_nents;
+};
+
+struct aead_ctx {
+       struct buffer_desc *buffer;
+       unsigned short assoc_nents;
+       unsigned short src_nents;
+       struct scatterlist ivlist;
+       /* used when the hmac is not on one sg entry */
+       u8 *hmac_virt;
+       int encrypt;
+};
+
+struct ix_hash_algo {
+       u32 cfgword;
+       unsigned char *icv;
+};
+
+struct ix_sa_dir {
+       unsigned char *npe_ctx;
+       dma_addr_t npe_ctx_phys;
+       int npe_ctx_idx;
+       u8 npe_mode;
+};
+
+struct ixp_ctx {
+       struct ix_sa_dir encrypt;
+       struct ix_sa_dir decrypt;
+       int authkey_len;
+       u8 authkey[MAX_KEYLEN];
+       int enckey_len;
+       u8 enckey[MAX_KEYLEN];
+       u8 salt[MAX_IVLEN];
+       u8 nonce[CTR_RFC3686_NONCE_SIZE];
+       unsigned salted;
+       atomic_t configuring;
+       struct completion completion;
+};
+
+struct ixp_alg {
+       struct crypto_alg crypto;
+       const struct ix_hash_algo *hash;
+       u32 cfg_enc;
+       u32 cfg_dec;
+
+       int registered;
+};
+
+static const struct ix_hash_algo hash_alg_md5 = {
+       .cfgword        = 0xAA010004,
+       .icv            = "\x01\x23\x45\x67\x89\xAB\xCD\xEF"
+                         "\xFE\xDC\xBA\x98\x76\x54\x32\x10",
+};
+static const struct ix_hash_algo hash_alg_sha1 = {
+       .cfgword        = 0x00000005,
+       .icv            = "\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA"
+                         "\xDC\xFE\x10\x32\x54\x76\xC3\xD2\xE1\xF0",
+};
+
+static struct npe *npe_c;
+static struct dma_pool *buffer_pool = NULL;
+static struct dma_pool *ctx_pool = NULL;
+
+static struct crypt_ctl *crypt_virt = NULL;
+static dma_addr_t crypt_phys;
+
+static int support_aes = 1;
+
+static void dev_release(struct device *dev)
+{
+       return;
+}
+
+#define DRIVER_NAME "ixp4xx_crypto"
+static struct platform_device pseudo_dev = {
+       .name = DRIVER_NAME,
+       .id   = 0,
+       .num_resources = 0,
+       .dev  = {
+               .coherent_dma_mask = DMA_32BIT_MASK,
+               .release = dev_release,
+       }
+};
+
+static struct device *dev = &pseudo_dev.dev;
+
+static inline dma_addr_t crypt_virt2phys(struct crypt_ctl *virt)
+{
+       return crypt_phys + (virt - crypt_virt) * sizeof(struct crypt_ctl);
+}
+
+static inline struct crypt_ctl *crypt_phys2virt(dma_addr_t phys)
+{
+       return crypt_virt + (phys - crypt_phys) / sizeof(struct crypt_ctl);
+}
+
+static inline u32 cipher_cfg_enc(struct crypto_tfm *tfm)
+{
+       return container_of(tfm->__crt_alg, struct ixp_alg,crypto)->cfg_enc;
+}
+
+static inline u32 cipher_cfg_dec(struct crypto_tfm *tfm)
+{
+       return container_of(tfm->__crt_alg, struct ixp_alg,crypto)->cfg_dec;
+}
+
+static inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm)
+{
+       return container_of(tfm->__crt_alg, struct ixp_alg, crypto)->hash;
+}
+
+static int setup_crypt_desc(void)
+{
+       BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64);
+       crypt_virt = dma_alloc_coherent(dev,
+                       NPE_QLEN * sizeof(struct crypt_ctl),
+                       &crypt_phys, GFP_KERNEL);
+       if (!crypt_virt)
+               return -ENOMEM;
+       memset(crypt_virt, 0, NPE_QLEN * sizeof(struct crypt_ctl));
+       return 0;
+}
+
+static spinlock_t desc_lock;
+static struct crypt_ctl *get_crypt_desc(void)
+{
+       int i;
+       static int idx = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc_lock, flags);
+
+       if (unlikely(!crypt_virt))
+               setup_crypt_desc();
+       if (unlikely(!crypt_virt)) {
+               spin_unlock_irqrestore(&desc_lock, flags);
+               return NULL;
+       }
+       i = idx;
+       if (crypt_virt[i].ctl_flags == CTL_FLAG_UNUSED) {
+               if (++idx >= NPE_QLEN)
+                       idx = 0;
+               crypt_virt[i].ctl_flags = CTL_FLAG_USED;
+               spin_unlock_irqrestore(&desc_lock, flags);
+               return crypt_virt +i;
+       } else {
+               spin_unlock_irqrestore(&desc_lock, flags);
+               return NULL;
+       }
+}
+
+static spinlock_t emerg_lock;
+static struct crypt_ctl *get_crypt_desc_emerg(void)
+{
+       int i;
+       static int idx = NPE_QLEN;
+       struct crypt_ctl *desc;
+       unsigned long flags;
+
+       desc = get_crypt_desc();
+       if (desc)
+               return desc;
+       if (unlikely(!crypt_virt))
+               return NULL;
+
+       spin_lock_irqsave(&emerg_lock, flags);
+       i = idx;
+       if (crypt_virt[i].ctl_flags == CTL_FLAG_UNUSED) {
+               if (++idx >= NPE_QLEN_TOTAL)
+                       idx = NPE_QLEN;
+               crypt_virt[i].ctl_flags = CTL_FLAG_USED;
+               spin_unlock_irqrestore(&emerg_lock, flags);
+               return crypt_virt +i;
+       } else {
+               spin_unlock_irqrestore(&emerg_lock, flags);
+               return NULL;
+       }
+}
+
+static void free_buf_chain(struct buffer_desc *buf, u32 phys)
+{
+       while (buf) {
+               struct buffer_desc *buf1;
+               u32 phys1;
+
+               buf1 = buf->next;
+               phys1 = buf->phys_next;
+               dma_pool_free(buffer_pool, buf, phys);
+               buf = buf1;
+               phys = phys1;
+       }
+}
+
+static struct tasklet_struct crypto_done_tasklet;
+
+static void finish_scattered_hmac(struct crypt_ctl *crypt)
+{
+       struct aead_request *req = crypt->data.aead_req;
+       struct aead_ctx *req_ctx = aead_request_ctx(req);
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       int authsize = crypto_aead_authsize(tfm);
+       int decryptlen = req->cryptlen - authsize;
+
+       if (req_ctx->encrypt) {
+               scatterwalk_map_and_copy(req_ctx->hmac_virt,
+                       req->src, decryptlen, authsize, 1);
+       }
+       dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes);
+}
+
+static void one_packet(dma_addr_t phys)
+{
+       struct crypt_ctl *crypt;
+       struct ixp_ctx *ctx;
+       int failed;
+       enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
+
+       failed = phys & 0x1 ? -EBADMSG : 0;
+       phys &= ~0x3;
+       crypt = crypt_phys2virt(phys);
+
+       switch (crypt->ctl_flags & CTL_FLAG_MASK) {
+       case CTL_FLAG_PERFORM_AEAD: {
+               struct aead_request *req = crypt->data.aead_req;
+               struct aead_ctx *req_ctx = aead_request_ctx(req);
+               dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents,
+                               DMA_TO_DEVICE);
+               dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
+               dma_unmap_sg(dev, req->src, req_ctx->src_nents,
+                               DMA_BIDIRECTIONAL);
+
+               free_buf_chain(req_ctx->buffer, crypt->src_buf);
+               if (req_ctx->hmac_virt) {
+                       finish_scattered_hmac(crypt);
+               }
+               req->base.complete(&req->base, failed);
+               break;
+       }
+       case CTL_FLAG_PERFORM_ABLK: {
+               struct ablkcipher_request *req = crypt->data.ablk_req;
+               struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req);
+               int nents;
+               if (req_ctx->dst) {
+                       nents = req_ctx->dst_nents;
+                       dma_unmap_sg(dev, req->dst, nents, DMA_FROM_DEVICE);
+                       free_buf_chain(req_ctx->dst, crypt->dst_buf);
+                       src_direction = DMA_TO_DEVICE;
+               }
+               nents = req_ctx->src_nents;
+               dma_unmap_sg(dev, req->src, nents, src_direction);
+               free_buf_chain(req_ctx->src, crypt->src_buf);
+               req->base.complete(&req->base, failed);
+               break;
+       }
+       case CTL_FLAG_GEN_ICV:
+               ctx = crypto_tfm_ctx(crypt->data.tfm);
+               dma_pool_free(ctx_pool, crypt->regist_ptr,
+                               crypt->regist_buf->phys_addr);
+               dma_pool_free(buffer_pool, crypt->regist_buf, crypt->src_buf);
+               if (atomic_dec_and_test(&ctx->configuring))
+                       complete(&ctx->completion);
+               break;
+       case CTL_FLAG_GEN_REVAES:
+               ctx = crypto_tfm_ctx(crypt->data.tfm);
+               *(u32*)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR);
+               if (atomic_dec_and_test(&ctx->configuring))
+                       complete(&ctx->completion);
+               break;
+       default:
+               BUG();
+       }
+       crypt->ctl_flags = CTL_FLAG_UNUSED;
+}
+
+static void irqhandler(void *_unused)
+{
+       tasklet_schedule(&crypto_done_tasklet);
+}
+
+static void crypto_done_action(unsigned long arg)
+{
+       int i;
+
+       for(i=0; i<4; i++) {
+               dma_addr_t phys = qmgr_get_entry(RECV_QID);
+               if (!phys)
+                       return;
+               one_packet(phys);
+       }
+       tasklet_schedule(&crypto_done_tasklet);
+}
+
+static int init_ixp_crypto(void)
+{
+       int ret = -ENODEV;
+
+       if (! ( ~(*IXP4XX_EXP_CFG2) & (IXP4XX_FEATURE_HASH |
+                               IXP4XX_FEATURE_AES | IXP4XX_FEATURE_DES))) {
+               printk(KERN_ERR "ixp_crypto: No HW crypto available\n");
+               return ret;
+       }
+       npe_c = npe_request(NPE_ID);
+       if (!npe_c)
+               return ret;
+
+       if (!npe_running(npe_c)) {
+               npe_load_firmware(npe_c, npe_name(npe_c), dev);
+       }
+
+       /* buffer_pool will also be used to sometimes store the hmac,
+        * so assure it is large enough
+        */
+       BUILD_BUG_ON(SHA1_DIGEST_SIZE > sizeof(struct buffer_desc));
+       buffer_pool = dma_pool_create("buffer", dev,
+                       sizeof(struct buffer_desc), 32, 0);
+       ret = -ENOMEM;
+       if (!buffer_pool) {
+               goto err;
+       }
+       ctx_pool = dma_pool_create("context", dev,
+                       NPE_CTX_LEN, 16, 0);
+       if (!ctx_pool) {
+               goto err;
+       }
+       ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0);
+       if (ret)
+               goto err;
+       ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0);
+       if (ret) {
+               qmgr_release_queue(SEND_QID);
+               goto err;
+       }
+       qmgr_set_irq(RECV_QID, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL);
+       tasklet_init(&crypto_done_tasklet, crypto_done_action, 0);
+
+       qmgr_enable_irq(RECV_QID);
+       return 0;
+err:
+       if (ctx_pool)
+               dma_pool_destroy(ctx_pool);
+       if (buffer_pool)
+               dma_pool_destroy(buffer_pool);
+       npe_release(npe_c);
+       return ret;
+}
+
+static void release_ixp_crypto(void)
+{
+       qmgr_disable_irq(RECV_QID);
+       tasklet_kill(&crypto_done_tasklet);
+
+       qmgr_release_queue(SEND_QID);
+       qmgr_release_queue(RECV_QID);
+
+       dma_pool_destroy(ctx_pool);
+       dma_pool_destroy(buffer_pool);
+
+       npe_release(npe_c);
+
+       if (crypt_virt) {
+               dma_free_coherent(dev,
+                       NPE_QLEN_TOTAL * sizeof( struct crypt_ctl),
+                       crypt_virt, crypt_phys);
+       }
+       return;
+}
+
+static void reset_sa_dir(struct ix_sa_dir *dir)
+{
+       memset(dir->npe_ctx, 0, NPE_CTX_LEN);
+       dir->npe_ctx_idx = 0;
+       dir->npe_mode = 0;
+}
+
+static int init_sa_dir(struct ix_sa_dir *dir)
+{
+       dir->npe_ctx = dma_pool_alloc(ctx_pool, GFP_KERNEL, &dir->npe_ctx_phys);
+       if (!dir->npe_ctx) {
+               return -ENOMEM;
+       }
+       reset_sa_dir(dir);
+       return 0;
+}
+
+static void free_sa_dir(struct ix_sa_dir *dir)
+{
+       memset(dir->npe_ctx, 0, NPE_CTX_LEN);
+       dma_pool_free(ctx_pool, dir->npe_ctx, dir->npe_ctx_phys);
+}
+
+static int init_tfm(struct crypto_tfm *tfm)
+{
+       struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+       int ret;
+
+       atomic_set(&ctx->configuring, 0);
+       ret = init_sa_dir(&ctx->encrypt);
+       if (ret)
+               return ret;
+       ret = init_sa_dir(&ctx->decrypt);
+       if (ret) {
+               free_sa_dir(&ctx->encrypt);
+       }
+       return ret;
+}
+
+static int init_tfm_ablk(struct crypto_tfm *tfm)
+{
+       tfm->crt_ablkcipher.reqsize = sizeof(struct ablk_ctx);
+       return init_tfm(tfm);
+}
+
+static int init_tfm_aead(struct crypto_tfm *tfm)
+{
+       tfm->crt_aead.reqsize = sizeof(struct aead_ctx);
+       return init_tfm(tfm);
+}
+
+static void exit_tfm(struct crypto_tfm *tfm)
+{
+       struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+       free_sa_dir(&ctx->encrypt);
+       free_sa_dir(&ctx->decrypt);
+}
+
+static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target,
+               int init_len, u32 ctx_addr, const u8 *key, int key_len)
+{
+       struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct crypt_ctl *crypt;
+       struct buffer_desc *buf;
+       int i;
+       u8 *pad;
+       u32 pad_phys, buf_phys;
+
+       BUILD_BUG_ON(NPE_CTX_LEN < HMAC_PAD_BLOCKLEN);
+       pad = dma_pool_alloc(ctx_pool, GFP_KERNEL, &pad_phys);
+       if (!pad)
+               return -ENOMEM;
+       buf = dma_pool_alloc(buffer_pool, GFP_KERNEL, &buf_phys);
+       if (!buf) {
+               dma_pool_free(ctx_pool, pad, pad_phys);
+               return -ENOMEM;
+       }
+       crypt = get_crypt_desc_emerg();
+       if (!crypt) {
+               dma_pool_free(ctx_pool, pad, pad_phys);
+               dma_pool_free(buffer_pool, buf, buf_phys);
+               return -EAGAIN;
+       }
+
+       memcpy(pad, key, key_len);
+       memset(pad + key_len, 0, HMAC_PAD_BLOCKLEN - key_len);
+       for (i = 0; i < HMAC_PAD_BLOCKLEN; i++) {
+               pad[i] ^= xpad;
+       }
+
+       crypt->data.tfm = tfm;
+       crypt->regist_ptr = pad;
+       crypt->regist_buf = buf;
+
+       crypt->auth_offs = 0;
+       crypt->auth_len = HMAC_PAD_BLOCKLEN;
+       crypt->crypto_ctx = ctx_addr;
+       crypt->src_buf = buf_phys;
+       crypt->icv_rev_aes = target;
+       crypt->mode = NPE_OP_HASH_GEN_ICV;
+       crypt->init_len = init_len;
+       crypt->ctl_flags |= CTL_FLAG_GEN_ICV;
+
+       buf->next = 0;
+       buf->buf_len = HMAC_PAD_BLOCKLEN;
+       buf->pkt_len = 0;
+       buf->phys_addr = pad_phys;
+
+       atomic_inc(&ctx->configuring);
+       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       return 0;
+}
+
+static int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize,
+               const u8 *key, int key_len, unsigned digest_len)
+{
+       u32 itarget, otarget, npe_ctx_addr;
+       unsigned char *cinfo;
+       int init_len, ret = 0;
+       u32 cfgword;
+       struct ix_sa_dir *dir;
+       struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+       const struct ix_hash_algo *algo;
+
+       dir = encrypt ? &ctx->encrypt : &ctx->decrypt;
+       cinfo = dir->npe_ctx + dir->npe_ctx_idx;
+       algo = ix_hash(tfm);
+
+       /* write cfg word to cryptinfo */
+       cfgword = algo->cfgword | ( authsize << 6); /* (authsize/4) << 8 */
+       *(u32*)cinfo = cpu_to_be32(cfgword);
+       cinfo += sizeof(cfgword);
+
+       /* write ICV to cryptinfo */
+       memcpy(cinfo, algo->icv, digest_len);
+       cinfo += digest_len;
+
+       itarget = dir->npe_ctx_phys + dir->npe_ctx_idx
+                               + sizeof(algo->cfgword);
+       otarget = itarget + digest_len;
+       init_len = cinfo - (dir->npe_ctx + dir->npe_ctx_idx);
+       npe_ctx_addr = dir->npe_ctx_phys + dir->npe_ctx_idx;
+
+       dir->npe_ctx_idx += init_len;
+       dir->npe_mode |= NPE_OP_HASH_ENABLE;
+
+       if (!encrypt)
+               dir->npe_mode |= NPE_OP_HASH_VERIFY;
+
+       ret = register_chain_var(tfm, HMAC_OPAD_VALUE, otarget,
+                       init_len, npe_ctx_addr, key, key_len);
+       if (ret)
+               return ret;
+       return register_chain_var(tfm, HMAC_IPAD_VALUE, itarget,
+                       init_len, npe_ctx_addr, key, key_len);
+}
+
+static int gen_rev_aes_key(struct crypto_tfm *tfm)
+{
+       struct crypt_ctl *crypt;
+       struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct ix_sa_dir *dir = &ctx->decrypt;
+
+       crypt = get_crypt_desc_emerg();
+       if (!crypt) {
+               return -EAGAIN;
+       }
+       *(u32*)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR);
+
+       crypt->data.tfm = tfm;
+       crypt->crypt_offs = 0;
+       crypt->crypt_len = AES_BLOCK128;
+       crypt->src_buf = 0;
+       crypt->crypto_ctx = dir->npe_ctx_phys;
+       crypt->icv_rev_aes = dir->npe_ctx_phys + sizeof(u32);
+       crypt->mode = NPE_OP_ENC_GEN_KEY;
+       crypt->init_len = dir->npe_ctx_idx;
+       crypt->ctl_flags |= CTL_FLAG_GEN_REVAES;
+
+       atomic_inc(&ctx->configuring);
+       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       return 0;
+}
+
+static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
+               const u8 *key, int key_len)
+{
+       u8 *cinfo;
+       u32 cipher_cfg;
+       u32 keylen_cfg = 0;
+       struct ix_sa_dir *dir;
+       struct ixp_ctx *ctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+
+       dir = encrypt ? &ctx->encrypt : &ctx->decrypt;
+       cinfo = dir->npe_ctx;
+
+       if (encrypt) {
+               cipher_cfg = cipher_cfg_enc(tfm);
+               dir->npe_mode |= NPE_OP_CRYPT_ENCRYPT;
+       } else {
+               cipher_cfg = cipher_cfg_dec(tfm);
+       }
+       if (cipher_cfg & MOD_AES) {
+               switch (key_len) {
+                       case 16: keylen_cfg = MOD_AES128 | KEYLEN_128; break;
+                       case 24: keylen_cfg = MOD_AES192 | KEYLEN_192; break;
+                       case 32: keylen_cfg = MOD_AES256 | KEYLEN_256; break;
+                       default:
+                               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+                               return -EINVAL;
+               }
+               cipher_cfg |= keylen_cfg;
+       } else if (cipher_cfg & MOD_3DES) {
+               const u32 *K = (const u32 *)key;
+               if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+                            !((K[2] ^ K[4]) | (K[3] ^ K[5]))))
+               {
+                       *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+                       return -EINVAL;
+               }
+       } else {
+               u32 tmp[DES_EXPKEY_WORDS];
+               if (des_ekey(tmp, key) == 0) {
+                       *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+               }
+       }
+       /* write cfg word to cryptinfo */
+       *(u32*)cinfo = cpu_to_be32(cipher_cfg);
+       cinfo += sizeof(cipher_cfg);
+
+       /* write cipher key to cryptinfo */
+       memcpy(cinfo, key, key_len);
+       /* NPE wants keylen set to DES3_EDE_KEY_SIZE even for single DES */
+       if (key_len < DES3_EDE_KEY_SIZE && !(cipher_cfg & MOD_AES)) {
+               memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE -key_len);
+               key_len = DES3_EDE_KEY_SIZE;
+       }
+       dir->npe_ctx_idx = sizeof(cipher_cfg) + key_len;
+       dir->npe_mode |= NPE_OP_CRYPT_ENABLE;
+       if ((cipher_cfg & MOD_AES) && !encrypt) {
+               return gen_rev_aes_key(tfm);
+       }
+       return 0;
+}
+
+static int count_sg(struct scatterlist *sg, int nbytes)
+{
+       int i;
+       for (i = 0; nbytes > 0; i++, sg = sg_next(sg))
+               nbytes -= sg->length;
+       return i;
+}
+
+static struct buffer_desc *chainup_buffers(struct scatterlist *sg,
+                       unsigned nbytes, struct buffer_desc *buf, gfp_t flags)
+{
+       int nents = 0;
+
+       while (nbytes > 0) {
+               struct buffer_desc *next_buf;
+               u32 next_buf_phys;
+               unsigned len = min(nbytes, sg_dma_len(sg));
+
+               nents++;
+               nbytes -= len;
+               if (!buf->phys_addr) {
+                       buf->phys_addr = sg_dma_address(sg);
+                       buf->buf_len = len;
+                       buf->next = NULL;
+                       buf->phys_next = 0;
+                       goto next;
+               }
+               /* Two consecutive chunks on one page may be handled by the old
+                * buffer descriptor, increased by the length of the new one
+                */
+               if (sg_dma_address(sg) == buf->phys_addr + buf->buf_len) {
+                       buf->buf_len += len;
+                       goto next;
+               }
+               next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys);
+               if (!next_buf)
+                       return NULL;
+               buf->next = next_buf;
+               buf->phys_next = next_buf_phys;
+
+               buf = next_buf;
+               buf->next = NULL;
+               buf->phys_next = 0;
+               buf->phys_addr = sg_dma_address(sg);
+               buf->buf_len = len;
+next:
+               if (nbytes > 0) {
+                       sg = sg_next(sg);
+               }
+       }
+       return buf;
+}
+
+static int ablk_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+                       unsigned int key_len)
+{
+       struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       u32 *flags = &tfm->base.crt_flags;
+       int ret;
+
+       init_completion(&ctx->completion);
+       atomic_inc(&ctx->configuring);
+
+       reset_sa_dir(&ctx->encrypt);
+       reset_sa_dir(&ctx->decrypt);
+
+       ctx->encrypt.npe_mode = NPE_OP_HMAC_DISABLE;
+       ctx->decrypt.npe_mode = NPE_OP_HMAC_DISABLE;
+
+       ret = setup_cipher(&tfm->base, 0, key, key_len);
+       if (ret)
+               goto out;
+       ret = setup_cipher(&tfm->base, 1, key, key_len);
+       if (ret)
+               goto out;
+
+       if (*flags & CRYPTO_TFM_RES_WEAK_KEY) {
+               if (*flags & CRYPTO_TFM_REQ_WEAK_KEY) {
+                       ret = -EINVAL;
+               } else {
+                       *flags &= ~CRYPTO_TFM_RES_WEAK_KEY;
+               }
+       }
+out:
+       if (!atomic_dec_and_test(&ctx->configuring))
+               wait_for_completion(&ctx->completion);
+       return ret;
+}
+
+static int ablk_rfc3686_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+               unsigned int key_len)
+{
+       struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+       /* the nonce is stored in bytes at end of key */
+       if (key_len < CTR_RFC3686_NONCE_SIZE)
+               return -EINVAL;
+
+       memcpy(ctx->nonce, key + (key_len - CTR_RFC3686_NONCE_SIZE),
+                       CTR_RFC3686_NONCE_SIZE);
+
+       key_len -= CTR_RFC3686_NONCE_SIZE;
+       return ablk_setkey(tfm, key, key_len);
+}
+
+static int ablk_perform(struct ablkcipher_request *req, int encrypt)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
+       int ret = -ENOMEM;
+       struct ix_sa_dir *dir;
+       struct crypt_ctl *crypt;
+       unsigned int nbytes = req->nbytes, nents;
+       enum dma_data_direction src_direction = DMA_BIDIRECTIONAL;
+       struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req);
+       gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+                               GFP_KERNEL : GFP_ATOMIC;
+
+       if (qmgr_stat_full(SEND_QID))
+               return -EAGAIN;
+       if (atomic_read(&ctx->configuring))
+               return -EAGAIN;
+
+       dir = encrypt ? &ctx->encrypt : &ctx->decrypt;
+
+       crypt = get_crypt_desc();
+       if (!crypt)
+               return ret;
+
+       crypt->data.ablk_req = req;
+       crypt->crypto_ctx = dir->npe_ctx_phys;
+       crypt->mode = dir->npe_mode;
+       crypt->init_len = dir->npe_ctx_idx;
+
+       crypt->crypt_offs = 0;
+       crypt->crypt_len = nbytes;
+
+       BUG_ON(ivsize && !req->info);
+       memcpy(crypt->iv, req->info, ivsize);
+       if (req->src != req->dst) {
+               crypt->mode |= NPE_OP_NOT_IN_PLACE;
+               nents = count_sg(req->dst, nbytes);
+               /* This was never tested by Intel
+                * for more than one dst buffer, I think. */
+               BUG_ON(nents != 1);
+               req_ctx->dst_nents = nents;
+               dma_map_sg(dev, req->dst, nents, DMA_FROM_DEVICE);
+               req_ctx->dst = dma_pool_alloc(buffer_pool, flags,&crypt->dst_buf);
+               if (!req_ctx->dst)
+                       goto unmap_sg_dest;
+               req_ctx->dst->phys_addr = 0;
+               if (!chainup_buffers(req->dst, nbytes, req_ctx->dst, flags))
+                       goto free_buf_dest;
+               src_direction = DMA_TO_DEVICE;
+       } else {
+               req_ctx->dst = NULL;
+               req_ctx->dst_nents = 0;
+       }
+       nents = count_sg(req->src, nbytes);
+       req_ctx->src_nents = nents;
+       dma_map_sg(dev, req->src, nents, src_direction);
+
+       req_ctx->src = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf);
+       if (!req_ctx->src)
+               goto unmap_sg_src;
+       req_ctx->src->phys_addr = 0;
+       if (!chainup_buffers(req->src, nbytes, req_ctx->src, flags))
+               goto free_buf_src;
+
+       crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK;
+       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       return -EINPROGRESS;
+
+free_buf_src:
+       free_buf_chain(req_ctx->src, crypt->src_buf);
+unmap_sg_src:
+       dma_unmap_sg(dev, req->src, req_ctx->src_nents, src_direction);
+free_buf_dest:
+       if (req->src != req->dst) {
+               free_buf_chain(req_ctx->dst, crypt->dst_buf);
+unmap_sg_dest:
+               dma_unmap_sg(dev, req->src, req_ctx->dst_nents,
+                       DMA_FROM_DEVICE);
+       }
+       crypt->ctl_flags = CTL_FLAG_UNUSED;
+       return ret;
+}
+
+static int ablk_encrypt(struct ablkcipher_request *req)
+{
+       return ablk_perform(req, 1);
+}
+
+static int ablk_decrypt(struct ablkcipher_request *req)
+{
+       return ablk_perform(req, 0);
+}
+
+static int ablk_rfc3686_crypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       u8 iv[CTR_RFC3686_BLOCK_SIZE];
+       u8 *info = req->info;
+       int ret;
+
+       /* set up counter block */
+        memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
+       memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE);
+
+       /* initialize counter portion of counter block */
+       *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
+               cpu_to_be32(1);
+
+       req->info = iv;
+       ret = ablk_perform(req, 1);
+       req->info = info;
+       return ret;
+}
+
+static int hmac_inconsistent(struct scatterlist *sg, unsigned start,
+               unsigned int nbytes)
+{
+       int offset = 0;
+
+       if (!nbytes)
+               return 0;
+
+       for (;;) {
+               if (start < offset + sg->length)
+                       break;
+
+               offset += sg->length;
+               sg = sg_next(sg);
+       }
+       return (start + nbytes > offset + sg->length);
+}
+
+static int aead_perform(struct aead_request *req, int encrypt,
+               int cryptoffset, int eff_cryptlen, u8 *iv)
+{
+       struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+       struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned ivsize = crypto_aead_ivsize(tfm);
+       unsigned authsize = crypto_aead_authsize(tfm);
+       int ret = -ENOMEM;
+       struct ix_sa_dir *dir;
+       struct crypt_ctl *crypt;
+       unsigned int cryptlen, nents;
+       struct buffer_desc *buf;
+       struct aead_ctx *req_ctx = aead_request_ctx(req);
+       gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+                               GFP_KERNEL : GFP_ATOMIC;
+
+       if (qmgr_stat_full(SEND_QID))
+               return -EAGAIN;
+       if (atomic_read(&ctx->configuring))
+               return -EAGAIN;
+
+       if (encrypt) {
+               dir = &ctx->encrypt;
+               cryptlen = req->cryptlen;
+       } else {
+               dir = &ctx->decrypt;
+               /* req->cryptlen includes the authsize when decrypting */
+               cryptlen = req->cryptlen -authsize;
+               eff_cryptlen -= authsize;
+       }
+       crypt = get_crypt_desc();
+       if (!crypt)
+               return ret;
+
+       crypt->data.aead_req = req;
+       crypt->crypto_ctx = dir->npe_ctx_phys;
+       crypt->mode = dir->npe_mode;
+       crypt->init_len = dir->npe_ctx_idx;
+
+       crypt->crypt_offs = cryptoffset;
+       crypt->crypt_len = eff_cryptlen;
+
+       crypt->auth_offs = 0;
+       crypt->auth_len = req->assoclen + ivsize + cryptlen;
+       BUG_ON(ivsize && !req->iv);
+       memcpy(crypt->iv, req->iv, ivsize);
+
+       if (req->src != req->dst) {
+               BUG(); /* -ENOTSUP because of my lazyness */
+       }
+
+       req_ctx->buffer = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf);
+       if (!req_ctx->buffer)
+               goto out;
+       req_ctx->buffer->phys_addr = 0;
+       /* ASSOC data */
+       nents = count_sg(req->assoc, req->assoclen);
+       req_ctx->assoc_nents = nents;
+       dma_map_sg(dev, req->assoc, nents, DMA_TO_DEVICE);
+       buf = chainup_buffers(req->assoc, req->assoclen, req_ctx->buffer,flags);
+       if (!buf)
+               goto unmap_sg_assoc;
+       /* IV */
+       sg_init_table(&req_ctx->ivlist, 1);
+       sg_set_buf(&req_ctx->ivlist, iv, ivsize);
+       dma_map_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
+       buf = chainup_buffers(&req_ctx->ivlist, ivsize, buf, flags);
+       if (!buf)
+               goto unmap_sg_iv;
+       if (unlikely(hmac_inconsistent(req->src, cryptlen, authsize))) {
+               /* The 12 hmac bytes are scattered,
+                * we need to copy them into a safe buffer */
+               req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags,
+                               &crypt->icv_rev_aes);
+               if (unlikely(!req_ctx->hmac_virt))
+                       goto unmap_sg_iv;
+               if (!encrypt) {
+                       scatterwalk_map_and_copy(req_ctx->hmac_virt,
+                               req->src, cryptlen, authsize, 0);
+               }
+               req_ctx->encrypt = encrypt;
+       } else {
+               req_ctx->hmac_virt = NULL;
+       }
+       /* Crypt */
+       nents = count_sg(req->src, cryptlen + authsize);
+       req_ctx->src_nents = nents;
+       dma_map_sg(dev, req->src, nents, DMA_BIDIRECTIONAL);
+       buf = chainup_buffers(req->src, cryptlen + authsize, buf, flags);
+       if (!buf)
+               goto unmap_sg_src;
+       if (!req_ctx->hmac_virt) {
+               crypt->icv_rev_aes = buf->phys_addr + buf->buf_len - authsize;
+       }
+       crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD;
+       qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt));
+       BUG_ON(qmgr_stat_overflow(SEND_QID));
+       return -EINPROGRESS;
+unmap_sg_src:
+       dma_unmap_sg(dev, req->src, req_ctx->src_nents, DMA_BIDIRECTIONAL);
+       if (req_ctx->hmac_virt) {
+               dma_pool_free(buffer_pool, req_ctx->hmac_virt,
+                               crypt->icv_rev_aes);
+       }
+unmap_sg_iv:
+       dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL);
+unmap_sg_assoc:
+       dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents, DMA_TO_DEVICE);
+       free_buf_chain(req_ctx->buffer, crypt->src_buf);
+out:
+       crypt->ctl_flags = CTL_FLAG_UNUSED;
+       return ret;
+}
+
+static int aead_setup(struct crypto_aead *tfm, unsigned int authsize)
+{
+       struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
+       u32 *flags = &tfm->base.crt_flags;
+       unsigned digest_len = crypto_aead_alg(tfm)->maxauthsize;
+       int ret;
+
+       if (!ctx->enckey_len && !ctx->authkey_len)
+               return 0;
+       init_completion(&ctx->completion);
+       atomic_inc(&ctx->configuring);
+
+       reset_sa_dir(&ctx->encrypt);
+       reset_sa_dir(&ctx->decrypt);
+
+       ret = setup_cipher(&tfm->base, 0, ctx->enckey, ctx->enckey_len);
+       if (ret)
+               goto out;
+       ret = setup_cipher(&tfm->base, 1, ctx->enckey, ctx->enckey_len);
+       if (ret)
+               goto out;
+       ret = setup_auth(&tfm->base, 0, authsize, ctx->authkey,
+                       ctx->authkey_len, digest_len);
+       if (ret)
+               goto out;
+       ret = setup_auth(&tfm->base, 1, authsize,  ctx->authkey,
+                       ctx->authkey_len, digest_len);
+       if (ret)
+               goto out;
+
+       if (*flags & CRYPTO_TFM_RES_WEAK_KEY) {
+               if (*flags & CRYPTO_TFM_REQ_WEAK_KEY) {
+                       ret = -EINVAL;
+                       goto out;
+               } else {
+                       *flags &= ~CRYPTO_TFM_RES_WEAK_KEY;
+               }
+       }
+out:
+       if (!atomic_dec_and_test(&ctx->configuring))
+               wait_for_completion(&ctx->completion);
+       return ret;
+}
+
+static int aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
+{
+       int max = crypto_aead_alg(tfm)->maxauthsize >> 2;
+
+       if ((authsize>>2) < 1 || (authsize>>2) > max || (authsize & 3))
+               return -EINVAL;
+       return aead_setup(tfm, authsize);
+}
+
+static int aead_setkey(struct crypto_aead *tfm, const u8 *key,
+                       unsigned int keylen)
+{
+       struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
+       struct rtattr *rta = (struct rtattr *)key;
+       struct crypto_authenc_key_param *param;
+
+       if (!RTA_OK(rta, keylen))
+               goto badkey;
+       if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+               goto badkey;
+       if (RTA_PAYLOAD(rta) < sizeof(*param))
+               goto badkey;
+
+       param = RTA_DATA(rta);
+       ctx->enckey_len = be32_to_cpu(param->enckeylen);
+
+       key += RTA_ALIGN(rta->rta_len);
+       keylen -= RTA_ALIGN(rta->rta_len);
+
+       if (keylen < ctx->enckey_len)
+               goto badkey;
+
+       ctx->authkey_len = keylen - ctx->enckey_len;
+       memcpy(ctx->enckey, key + ctx->authkey_len, ctx->enckey_len);
+       memcpy(ctx->authkey, key, ctx->authkey_len);
+
+       return aead_setup(tfm, crypto_aead_authsize(tfm));
+badkey:
+       ctx->enckey_len = 0;
+       crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+       return -EINVAL;
+}
+
+static int aead_encrypt(struct aead_request *req)
+{
+       unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req));
+       return aead_perform(req, 1, req->assoclen + ivsize,
+                       req->cryptlen, req->iv);
+}
+
+static int aead_decrypt(struct aead_request *req)
+{
+       unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req));
+       return aead_perform(req, 0, req->assoclen + ivsize,
+                       req->cryptlen, req->iv);
+}
+
+static int aead_givencrypt(struct aead_givcrypt_request *req)
+{
+       struct crypto_aead *tfm = aead_givcrypt_reqtfm(req);
+       struct ixp_ctx *ctx = crypto_aead_ctx(tfm);
+       unsigned len, ivsize = crypto_aead_ivsize(tfm);
+       __be64 seq;
+
+       /* copied from eseqiv.c */
+       if (!ctx->salted) {
+               get_random_bytes(ctx->salt, ivsize);
+               ctx->salted = 1;
+       }
+       memcpy(req->areq.iv, ctx->salt, ivsize);
+       len = ivsize;
+       if (ivsize > sizeof(u64)) {
+               memset(req->giv, 0, ivsize - sizeof(u64));
+               len = sizeof(u64);
+       }
+       seq = cpu_to_be64(req->seq);
+       memcpy(req->giv + ivsize - len, &seq, len);
+       return aead_perform(&req->areq, 1, req->areq.assoclen,
+                       req->areq.cryptlen +ivsize, req->giv);
+}
+
+static struct ixp_alg ixp4xx_algos[] = {
+{
+       .crypto = {
+               .cra_name       = "cbc(des)",
+               .cra_blocksize  = DES_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = DES_KEY_SIZE,
+                       .max_keysize    = DES_KEY_SIZE,
+                       .ivsize         = DES_BLOCK_SIZE,
+                       .geniv          = "eseqiv",
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192,
+
+}, {
+       .crypto = {
+               .cra_name       = "ecb(des)",
+               .cra_blocksize  = DES_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = DES_KEY_SIZE,
+                       .max_keysize    = DES_KEY_SIZE,
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_DES | MOD_ECB | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_DES | MOD_ECB | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "cbc(des3_ede)",
+               .cra_blocksize  = DES3_EDE_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = DES3_EDE_KEY_SIZE,
+                       .max_keysize    = DES3_EDE_KEY_SIZE,
+                       .ivsize         = DES3_EDE_BLOCK_SIZE,
+                       .geniv          = "eseqiv",
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "ecb(des3_ede)",
+               .cra_blocksize  = DES3_EDE_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = DES3_EDE_KEY_SIZE,
+                       .max_keysize    = DES3_EDE_KEY_SIZE,
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_ECB | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_3DES | MOD_ECB | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "cbc(aes)",
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .geniv          = "eseqiv",
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC,
+       .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC,
+}, {
+       .crypto = {
+               .cra_name       = "ecb(aes)",
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_AES | MOD_ECB,
+       .cfg_dec = CIPH_DECR | MOD_AES | MOD_ECB,
+}, {
+       .crypto = {
+               .cra_name       = "ctr(aes)",
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .geniv          = "eseqiv",
+                       }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR,
+       .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR,
+}, {
+       .crypto = {
+               .cra_name       = "rfc3686(ctr(aes))",
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_u          = { .ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .geniv          = "eseqiv",
+                       .setkey         = ablk_rfc3686_setkey,
+                       .encrypt        = ablk_rfc3686_crypt,
+                       .decrypt        = ablk_rfc3686_crypt }
+               }
+       },
+       .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR,
+       .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR,
+}, {
+       .crypto = {
+               .cra_name       = "authenc(hmac(md5),cbc(des))",
+               .cra_blocksize  = DES_BLOCK_SIZE,
+               .cra_u          = { .aead = {
+                       .ivsize         = DES_BLOCK_SIZE,
+                       .maxauthsize    = MD5_DIGEST_SIZE,
+                       }
+               }
+       },
+       .hash = &hash_alg_md5,
+       .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "authenc(hmac(md5),cbc(des3_ede))",
+               .cra_blocksize  = DES3_EDE_BLOCK_SIZE,
+               .cra_u          = { .aead = {
+                       .ivsize         = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize    = MD5_DIGEST_SIZE,
+                       }
+               }
+       },
+       .hash = &hash_alg_md5,
+       .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "authenc(hmac(sha1),cbc(des))",
+               .cra_blocksize  = DES_BLOCK_SIZE,
+               .cra_u          = { .aead = {
+                       .ivsize         = DES_BLOCK_SIZE,
+                       .maxauthsize    = SHA1_DIGEST_SIZE,
+                       }
+               }
+       },
+       .hash = &hash_alg_sha1,
+       .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "authenc(hmac(sha1),cbc(des3_ede))",
+               .cra_blocksize  = DES3_EDE_BLOCK_SIZE,
+               .cra_u          = { .aead = {
+                       .ivsize         = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize    = SHA1_DIGEST_SIZE,
+                       }
+               }
+       },
+       .hash = &hash_alg_sha1,
+       .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192,
+       .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192,
+}, {
+       .crypto = {
+               .cra_name       = "authenc(hmac(md5),cbc(aes))",
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_u          = { .aead = {
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .maxauthsize    = MD5_DIGEST_SIZE,
+                       }
+               }
+       },
+       .hash = &hash_alg_md5,
+       .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC,
+       .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC,
+}, {
+       .crypto = {
+               .cra_name       = "authenc(hmac(sha1),cbc(aes))",
+               .cra_blocksize  = AES_BLOCK_SIZE,
+               .cra_u          = { .aead = {
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .maxauthsize    = SHA1_DIGEST_SIZE,
+                       }
+               }
+       },
+       .hash = &hash_alg_sha1,
+       .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC,
+       .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC,
+} };
+
+#define IXP_POSTFIX "-ixp4xx"
+static int __init ixp_module_init(void)
+{
+       int num = ARRAY_SIZE(ixp4xx_algos);
+       int i,err ;
+
+       if (platform_device_register(&pseudo_dev))
+               return -ENODEV;
+
+       spin_lock_init(&desc_lock);
+       spin_lock_init(&emerg_lock);
+
+       err = init_ixp_crypto();
+       if (err) {
+               platform_device_unregister(&pseudo_dev);
+               return err;
+       }
+       for (i=0; i< num; i++) {
+               struct crypto_alg *cra = &ixp4xx_algos[i].crypto;
+
+               if (snprintf(cra->cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                       "%s"IXP_POSTFIX, cra->cra_name) >=
+                       CRYPTO_MAX_ALG_NAME)
+               {
+                       continue;
+               }
+               if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) {
+                       continue;
+               }
+               if (!ixp4xx_algos[i].hash) {
+                       /* block ciphers */
+                       cra->cra_type = &crypto_ablkcipher_type;
+                       cra->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                        CRYPTO_ALG_ASYNC;
+                       if (!cra->cra_ablkcipher.setkey)
+                               cra->cra_ablkcipher.setkey = ablk_setkey;
+                       if (!cra->cra_ablkcipher.encrypt)
+                               cra->cra_ablkcipher.encrypt = ablk_encrypt;
+                       if (!cra->cra_ablkcipher.decrypt)
+                               cra->cra_ablkcipher.decrypt = ablk_decrypt;
+                       cra->cra_init = init_tfm_ablk;
+               } else {
+                       /* authenc */
+                       cra->cra_type = &crypto_aead_type;
+                       cra->cra_flags = CRYPTO_ALG_TYPE_AEAD |
+                                        CRYPTO_ALG_ASYNC;
+                       cra->cra_aead.setkey = aead_setkey;
+                       cra->cra_aead.setauthsize = aead_setauthsize;
+                       cra->cra_aead.encrypt = aead_encrypt;
+                       cra->cra_aead.decrypt = aead_decrypt;
+                       cra->cra_aead.givencrypt = aead_givencrypt;
+                       cra->cra_init = init_tfm_aead;
+               }
+               cra->cra_ctxsize = sizeof(struct ixp_ctx);
+               cra->cra_module = THIS_MODULE;
+               cra->cra_alignmask = 3;
+               cra->cra_priority = 300;
+               cra->cra_exit = exit_tfm;
+               if (crypto_register_alg(cra))
+                       printk(KERN_ERR "Failed to register '%s'\n",
+                               cra->cra_name);
+               else
+                       ixp4xx_algos[i].registered = 1;
+       }
+       return 0;
+}
+
+static void __exit ixp_module_exit(void)
+{
+       int num = ARRAY_SIZE(ixp4xx_algos);
+       int i;
+
+       for (i=0; i< num; i++) {
+               if (ixp4xx_algos[i].registered)
+                       crypto_unregister_alg(&ixp4xx_algos[i].crypto);
+       }
+       release_ixp_crypto();
+       platform_device_unregister(&pseudo_dev);
+}
+
+module_init(ixp_module_init);
+module_exit(ixp_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt@innominate.com>");
+MODULE_DESCRIPTION("IXP4xx hardware crypto");
+
index bb30eb9b93ef7539c3548d763235dc92a077831d..54a2a166e566740f1ebae141495e09013015aeea 100644 (file)
@@ -385,12 +385,12 @@ static int __init padlock_init(void)
        int ret;
 
        if (!cpu_has_xcrypt) {
-               printk(KERN_ERR PFX "VIA PadLock not detected.\n");
+               printk(KERN_NOTICE PFX "VIA PadLock not detected.\n");
                return -ENODEV;
        }
 
        if (!cpu_has_xcrypt_enabled) {
-               printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+               printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
                return -ENODEV;
        }
 
index c666b4e0933e422442e57abd833db4641c4c6949..40d5680fa0139c926ab500545736a3ac9abd0035 100644 (file)
@@ -254,12 +254,12 @@ static int __init padlock_init(void)
        int rc = -ENODEV;
 
        if (!cpu_has_phe) {
-               printk(KERN_ERR PFX "VIA PadLock Hash Engine not detected.\n");
+               printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n");
                return -ENODEV;
        }
 
        if (!cpu_has_phe_enabled) {
-               printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+               printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
                return -ENODEV;
        }
 
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
new file mode 100644 (file)
index 0000000..b11943d
--- /dev/null
@@ -0,0 +1,1597 @@
+/*
+ * talitos - Freescale Integrated Security Engine (SEC) device driver
+ *
+ * Copyright (c) 2008 Freescale Semiconductor, Inc.
+ *
+ * Scatterlist Crypto API glue code copied from files with the following:
+ * Copyright (c) 2006-2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * Crypto algorithm registration code copied from hifn driver:
+ * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <crypto/sha.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+
+#include "talitos.h"
+
+#define TALITOS_TIMEOUT 100000
+#define TALITOS_MAX_DATA_LEN 65535
+
+#define DESC_TYPE(desc_hdr) ((be32_to_cpu(desc_hdr) >> 3) & 0x1f)
+#define PRIMARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 28) & 0xf)
+#define SECONDARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 16) & 0xf)
+
+/* descriptor pointer entry */
+struct talitos_ptr {
+       __be16 len;     /* length */
+       u8 j_extent;    /* jump to sg link table and/or extent */
+       u8 eptr;        /* extended address */
+       __be32 ptr;     /* address */
+};
+
+/* descriptor */
+struct talitos_desc {
+       __be32 hdr;                     /* header high bits */
+       __be32 hdr_lo;                  /* header low bits */
+       struct talitos_ptr ptr[7];      /* ptr/len pair array */
+};
+
+/**
+ * talitos_request - descriptor submission request
+ * @desc: descriptor pointer (kernel virtual)
+ * @dma_desc: descriptor's physical bus address
+ * @callback: whom to call when descriptor processing is done
+ * @context: caller context (optional)
+ */
+struct talitos_request {
+       struct talitos_desc *desc;
+       dma_addr_t dma_desc;
+       void (*callback) (struct device *dev, struct talitos_desc *desc,
+                         void *context, int error);
+       void *context;
+};
+
+struct talitos_private {
+       struct device *dev;
+       struct of_device *ofdev;
+       void __iomem *reg;
+       int irq;
+
+       /* SEC version geometry (from device tree node) */
+       unsigned int num_channels;
+       unsigned int chfifo_len;
+       unsigned int exec_units;
+       unsigned int desc_types;
+
+       /* next channel to be assigned next incoming descriptor */
+       atomic_t last_chan;
+
+       /* per-channel request fifo */
+       struct talitos_request **fifo;
+
+       /*
+        * length of the request fifo
+        * fifo_len is chfifo_len rounded up to next power of 2
+        * so we can use bitwise ops to wrap
+        */
+       unsigned int fifo_len;
+
+       /* per-channel index to next free descriptor request */
+       int *head;
+
+       /* per-channel index to next in-progress/done descriptor request */
+       int *tail;
+
+       /* per-channel request submission (head) and release (tail) locks */
+       spinlock_t *head_lock;
+       spinlock_t *tail_lock;
+
+       /* request callback tasklet */
+       struct tasklet_struct done_task;
+       struct tasklet_struct error_task;
+
+       /* list of registered algorithms */
+       struct list_head alg_list;
+
+       /* hwrng device */
+       struct hwrng rng;
+};
+
+/*
+ * map virtual single (contiguous) pointer to h/w descriptor pointer
+ */
+static void map_single_talitos_ptr(struct device *dev,
+                                  struct talitos_ptr *talitos_ptr,
+                                  unsigned short len, void *data,
+                                  unsigned char extent,
+                                  enum dma_data_direction dir)
+{
+       talitos_ptr->len = cpu_to_be16(len);
+       talitos_ptr->ptr = cpu_to_be32(dma_map_single(dev, data, len, dir));
+       talitos_ptr->j_extent = extent;
+}
+
+/*
+ * unmap bus single (contiguous) h/w descriptor pointer
+ */
+static void unmap_single_talitos_ptr(struct device *dev,
+                                    struct talitos_ptr *talitos_ptr,
+                                    enum dma_data_direction dir)
+{
+       dma_unmap_single(dev, be32_to_cpu(talitos_ptr->ptr),
+                        be16_to_cpu(talitos_ptr->len), dir);
+}
+
+static int reset_channel(struct device *dev, int ch)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       unsigned int timeout = TALITOS_TIMEOUT;
+
+       setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_RESET);
+
+       while ((in_be32(priv->reg + TALITOS_CCCR(ch)) & TALITOS_CCCR_RESET)
+              && --timeout)
+               cpu_relax();
+
+       if (timeout == 0) {
+               dev_err(dev, "failed to reset channel %d\n", ch);
+               return -EIO;
+       }
+
+       /* set done writeback and IRQ */
+       setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE |
+                 TALITOS_CCCR_LO_CDIE);
+
+       return 0;
+}
+
+static int reset_device(struct device *dev)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       unsigned int timeout = TALITOS_TIMEOUT;
+
+       setbits32(priv->reg + TALITOS_MCR, TALITOS_MCR_SWR);
+
+       while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR)
+              && --timeout)
+               cpu_relax();
+
+       if (timeout == 0) {
+               dev_err(dev, "failed to reset device\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * Reset and initialize the device
+ */
+static int init_device(struct device *dev)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int ch, err;
+
+       /*
+        * Master reset
+        * errata documentation: warning: certain SEC interrupts
+        * are not fully cleared by writing the MCR:SWR bit,
+        * set bit twice to completely reset
+        */
+       err = reset_device(dev);
+       if (err)
+               return err;
+
+       err = reset_device(dev);
+       if (err)
+               return err;
+
+       /* reset channels */
+       for (ch = 0; ch < priv->num_channels; ch++) {
+               err = reset_channel(dev, ch);
+               if (err)
+                       return err;
+       }
+
+       /* enable channel done and error interrupts */
+       setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
+       setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
+
+       return 0;
+}
+
+/**
+ * talitos_submit - submits a descriptor to the device for processing
+ * @dev:       the SEC device to be used
+ * @desc:      the descriptor to be processed by the device
+ * @callback:  whom to call when processing is complete
+ * @context:   a handle for use by caller (optional)
+ *
+ * desc must contain valid dma-mapped (bus physical) address pointers.
+ * callback must check err and feedback in descriptor header
+ * for device processing status.
+ */
+static int talitos_submit(struct device *dev, struct talitos_desc *desc,
+                         void (*callback)(struct device *dev,
+                                          struct talitos_desc *desc,
+                                          void *context, int error),
+                         void *context)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       struct talitos_request *request;
+       unsigned long flags, ch;
+       int head;
+
+       /* select done notification */
+       desc->hdr |= DESC_HDR_DONE_NOTIFY;
+
+       /* emulate SEC's round-robin channel fifo polling scheme */
+       ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1);
+
+       spin_lock_irqsave(&priv->head_lock[ch], flags);
+
+       head = priv->head[ch];
+       request = &priv->fifo[ch][head];
+
+       if (request->desc) {
+               /* request queue is full */
+               spin_unlock_irqrestore(&priv->head_lock[ch], flags);
+               return -EAGAIN;
+       }
+
+       /* map descriptor and save caller data */
+       request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
+                                          DMA_BIDIRECTIONAL);
+       request->callback = callback;
+       request->context = context;
+
+       /* increment fifo head */
+       priv->head[ch] = (priv->head[ch] + 1) & (priv->fifo_len - 1);
+
+       smp_wmb();
+       request->desc = desc;
+
+       /* GO! */
+       wmb();
+       out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc);
+
+       spin_unlock_irqrestore(&priv->head_lock[ch], flags);
+
+       return -EINPROGRESS;
+}
+
+/*
+ * process what was done, notify callback of error if not
+ */
+static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       struct talitos_request *request, saved_req;
+       unsigned long flags;
+       int tail, status;
+
+       spin_lock_irqsave(&priv->tail_lock[ch], flags);
+
+       tail = priv->tail[ch];
+       while (priv->fifo[ch][tail].desc) {
+               request = &priv->fifo[ch][tail];
+
+               /* descriptors with their done bits set don't get the error */
+               rmb();
+               if ((request->desc->hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
+                       status = 0;
+               else
+                       if (!error)
+                               break;
+                       else
+                               status = error;
+
+               dma_unmap_single(dev, request->dma_desc,
+                       sizeof(struct talitos_desc), DMA_BIDIRECTIONAL);
+
+               /* copy entries so we can call callback outside lock */
+               saved_req.desc = request->desc;
+               saved_req.callback = request->callback;
+               saved_req.context = request->context;
+
+               /* release request entry in fifo */
+               smp_wmb();
+               request->desc = NULL;
+
+               /* increment fifo tail */
+               priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1);
+
+               spin_unlock_irqrestore(&priv->tail_lock[ch], flags);
+               saved_req.callback(dev, saved_req.desc, saved_req.context,
+                                  status);
+               /* channel may resume processing in single desc error case */
+               if (error && !reset_ch && status == error)
+                       return;
+               spin_lock_irqsave(&priv->tail_lock[ch], flags);
+               tail = priv->tail[ch];
+       }
+
+       spin_unlock_irqrestore(&priv->tail_lock[ch], flags);
+}
+
+/*
+ * process completed requests for channels that have done status
+ */
+static void talitos_done(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int ch;
+
+       for (ch = 0; ch < priv->num_channels; ch++)
+               flush_channel(dev, ch, 0, 0);
+}
+
+/*
+ * locate current (offending) descriptor
+ */
+static struct talitos_desc *current_desc(struct device *dev, int ch)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int tail = priv->tail[ch];
+       dma_addr_t cur_desc;
+
+       cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch));
+
+       while (priv->fifo[ch][tail].dma_desc != cur_desc) {
+               tail = (tail + 1) & (priv->fifo_len - 1);
+               if (tail == priv->tail[ch]) {
+                       dev_err(dev, "couldn't locate current descriptor\n");
+                       return NULL;
+               }
+       }
+
+       return priv->fifo[ch][tail].desc;
+}
+
+/*
+ * user diagnostics; report root cause of error based on execution unit status
+ */
+static void report_eu_error(struct device *dev, int ch, struct talitos_desc *desc)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int i;
+
+       switch (desc->hdr & DESC_HDR_SEL0_MASK) {
+       case DESC_HDR_SEL0_AFEU:
+               dev_err(dev, "AFEUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_AFEUISR),
+                       in_be32(priv->reg + TALITOS_AFEUISR_LO));
+               break;
+       case DESC_HDR_SEL0_DEU:
+               dev_err(dev, "DEUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_DEUISR),
+                       in_be32(priv->reg + TALITOS_DEUISR_LO));
+               break;
+       case DESC_HDR_SEL0_MDEUA:
+       case DESC_HDR_SEL0_MDEUB:
+               dev_err(dev, "MDEUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_MDEUISR),
+                       in_be32(priv->reg + TALITOS_MDEUISR_LO));
+               break;
+       case DESC_HDR_SEL0_RNG:
+               dev_err(dev, "RNGUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_RNGUISR),
+                       in_be32(priv->reg + TALITOS_RNGUISR_LO));
+               break;
+       case DESC_HDR_SEL0_PKEU:
+               dev_err(dev, "PKEUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_PKEUISR),
+                       in_be32(priv->reg + TALITOS_PKEUISR_LO));
+               break;
+       case DESC_HDR_SEL0_AESU:
+               dev_err(dev, "AESUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_AESUISR),
+                       in_be32(priv->reg + TALITOS_AESUISR_LO));
+               break;
+       case DESC_HDR_SEL0_CRCU:
+               dev_err(dev, "CRCUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_CRCUISR),
+                       in_be32(priv->reg + TALITOS_CRCUISR_LO));
+               break;
+       case DESC_HDR_SEL0_KEU:
+               dev_err(dev, "KEUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_KEUISR),
+                       in_be32(priv->reg + TALITOS_KEUISR_LO));
+               break;
+       }
+
+       switch (desc->hdr & DESC_HDR_SEL1_MASK) {
+       case DESC_HDR_SEL1_MDEUA:
+       case DESC_HDR_SEL1_MDEUB:
+               dev_err(dev, "MDEUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_MDEUISR),
+                       in_be32(priv->reg + TALITOS_MDEUISR_LO));
+               break;
+       case DESC_HDR_SEL1_CRCU:
+               dev_err(dev, "CRCUISR 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_CRCUISR),
+                       in_be32(priv->reg + TALITOS_CRCUISR_LO));
+               break;
+       }
+
+       for (i = 0; i < 8; i++)
+               dev_err(dev, "DESCBUF 0x%08x_%08x\n",
+                       in_be32(priv->reg + TALITOS_DESCBUF(ch) + 8*i),
+                       in_be32(priv->reg + TALITOS_DESCBUF_LO(ch) + 8*i));
+}
+
+/*
+ * recover from error interrupts
+ */
+static void talitos_error(unsigned long data)
+{
+       struct device *dev = (struct device *)data;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       unsigned int timeout = TALITOS_TIMEOUT;
+       int ch, error, reset_dev = 0, reset_ch = 0;
+       u32 isr, isr_lo, v, v_lo;
+
+       isr = in_be32(priv->reg + TALITOS_ISR);
+       isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
+
+       for (ch = 0; ch < priv->num_channels; ch++) {
+               /* skip channels without errors */
+               if (!(isr & (1 << (ch * 2 + 1))))
+                       continue;
+
+               error = -EINVAL;
+
+               v = in_be32(priv->reg + TALITOS_CCPSR(ch));
+               v_lo = in_be32(priv->reg + TALITOS_CCPSR_LO(ch));
+
+               if (v_lo & TALITOS_CCPSR_LO_DOF) {
+                       dev_err(dev, "double fetch fifo overflow error\n");
+                       error = -EAGAIN;
+                       reset_ch = 1;
+               }
+               if (v_lo & TALITOS_CCPSR_LO_SOF) {
+                       /* h/w dropped descriptor */
+                       dev_err(dev, "single fetch fifo overflow error\n");
+                       error = -EAGAIN;
+               }
+               if (v_lo & TALITOS_CCPSR_LO_MDTE)
+                       dev_err(dev, "master data transfer error\n");
+               if (v_lo & TALITOS_CCPSR_LO_SGDLZ)
+                       dev_err(dev, "s/g data length zero error\n");
+               if (v_lo & TALITOS_CCPSR_LO_FPZ)
+                       dev_err(dev, "fetch pointer zero error\n");
+               if (v_lo & TALITOS_CCPSR_LO_IDH)
+                       dev_err(dev, "illegal descriptor header error\n");
+               if (v_lo & TALITOS_CCPSR_LO_IEU)
+                       dev_err(dev, "invalid execution unit error\n");
+               if (v_lo & TALITOS_CCPSR_LO_EU)
+                       report_eu_error(dev, ch, current_desc(dev, ch));
+               if (v_lo & TALITOS_CCPSR_LO_GB)
+                       dev_err(dev, "gather boundary error\n");
+               if (v_lo & TALITOS_CCPSR_LO_GRL)
+                       dev_err(dev, "gather return/length error\n");
+               if (v_lo & TALITOS_CCPSR_LO_SB)
+                       dev_err(dev, "scatter boundary error\n");
+               if (v_lo & TALITOS_CCPSR_LO_SRL)
+                       dev_err(dev, "scatter return/length error\n");
+
+               flush_channel(dev, ch, error, reset_ch);
+
+               if (reset_ch) {
+                       reset_channel(dev, ch);
+               } else {
+                       setbits32(priv->reg + TALITOS_CCCR(ch),
+                                 TALITOS_CCCR_CONT);
+                       setbits32(priv->reg + TALITOS_CCCR_LO(ch), 0);
+                       while ((in_be32(priv->reg + TALITOS_CCCR(ch)) &
+                              TALITOS_CCCR_CONT) && --timeout)
+                               cpu_relax();
+                       if (timeout == 0) {
+                               dev_err(dev, "failed to restart channel %d\n",
+                                       ch);
+                               reset_dev = 1;
+                       }
+               }
+       }
+       if (reset_dev || isr & ~TALITOS_ISR_CHERR || isr_lo) {
+               dev_err(dev, "done overflow, internal time out, or rngu error: "
+                       "ISR 0x%08x_%08x\n", isr, isr_lo);
+
+               /* purge request queues */
+               for (ch = 0; ch < priv->num_channels; ch++)
+                       flush_channel(dev, ch, -EIO, 1);
+
+               /* reset and reinitialize the device */
+               init_device(dev);
+       }
+}
+
+static irqreturn_t talitos_interrupt(int irq, void *data)
+{
+       struct device *dev = data;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       u32 isr, isr_lo;
+
+       isr = in_be32(priv->reg + TALITOS_ISR);
+       isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
+
+       /* ack */
+       out_be32(priv->reg + TALITOS_ICR, isr);
+       out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
+
+       if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo))
+               talitos_error((unsigned long)data);
+       else
+               if (likely(isr & TALITOS_ISR_CHDONE))
+                       tasklet_schedule(&priv->done_task);
+
+       return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * hwrng
+ */
+static int talitos_rng_data_present(struct hwrng *rng, int wait)
+{
+       struct device *dev = (struct device *)rng->priv;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       u32 ofl;
+       int i;
+
+       for (i = 0; i < 20; i++) {
+               ofl = in_be32(priv->reg + TALITOS_RNGUSR_LO) &
+                     TALITOS_RNGUSR_LO_OFL;
+               if (ofl || !wait)
+                       break;
+               udelay(10);
+       }
+
+       return !!ofl;
+}
+
+static int talitos_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       struct device *dev = (struct device *)rng->priv;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+
+       /* rng fifo requires 64-bit accesses */
+       *data = in_be32(priv->reg + TALITOS_RNGU_FIFO);
+       *data = in_be32(priv->reg + TALITOS_RNGU_FIFO_LO);
+
+       return sizeof(u32);
+}
+
+static int talitos_rng_init(struct hwrng *rng)
+{
+       struct device *dev = (struct device *)rng->priv;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       unsigned int timeout = TALITOS_TIMEOUT;
+
+       setbits32(priv->reg + TALITOS_RNGURCR_LO, TALITOS_RNGURCR_LO_SR);
+       while (!(in_be32(priv->reg + TALITOS_RNGUSR_LO) & TALITOS_RNGUSR_LO_RD)
+              && --timeout)
+               cpu_relax();
+       if (timeout == 0) {
+               dev_err(dev, "failed to reset rng hw\n");
+               return -ENODEV;
+       }
+
+       /* start generating */
+       setbits32(priv->reg + TALITOS_RNGUDSR_LO, 0);
+
+       return 0;
+}
+
+static int talitos_register_rng(struct device *dev)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+
+       priv->rng.name          = dev_driver_string(dev),
+       priv->rng.init          = talitos_rng_init,
+       priv->rng.data_present  = talitos_rng_data_present,
+       priv->rng.data_read     = talitos_rng_data_read,
+       priv->rng.priv          = (unsigned long)dev;
+
+       return hwrng_register(&priv->rng);
+}
+
+static void talitos_unregister_rng(struct device *dev)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+
+       hwrng_unregister(&priv->rng);
+}
+
+/*
+ * crypto alg
+ */
+#define TALITOS_CRA_PRIORITY           3000
+#define TALITOS_MAX_KEY_SIZE           64
+#define TALITOS_MAX_IV_LENGTH          16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
+
+#define MD5_DIGEST_SIZE   16
+
+struct talitos_ctx {
+       struct device *dev;
+       __be32 desc_hdr_template;
+       u8 key[TALITOS_MAX_KEY_SIZE];
+       u8 iv[TALITOS_MAX_IV_LENGTH];
+       unsigned int keylen;
+       unsigned int enckeylen;
+       unsigned int authkeylen;
+       unsigned int authsize;
+};
+
+static int aead_authenc_setauthsize(struct crypto_aead *authenc,
+                                                unsigned int authsize)
+{
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+
+       ctx->authsize = authsize;
+
+       return 0;
+}
+
+static int aead_authenc_setkey(struct crypto_aead *authenc,
+                                           const u8 *key, unsigned int keylen)
+{
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct rtattr *rta = (void *)key;
+       struct crypto_authenc_key_param *param;
+       unsigned int authkeylen;
+       unsigned int enckeylen;
+
+       if (!RTA_OK(rta, keylen))
+               goto badkey;
+
+       if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+               goto badkey;
+
+       if (RTA_PAYLOAD(rta) < sizeof(*param))
+               goto badkey;
+
+       param = RTA_DATA(rta);
+       enckeylen = be32_to_cpu(param->enckeylen);
+
+       key += RTA_ALIGN(rta->rta_len);
+       keylen -= RTA_ALIGN(rta->rta_len);
+
+       if (keylen < enckeylen)
+               goto badkey;
+
+       authkeylen = keylen - enckeylen;
+
+       if (keylen > TALITOS_MAX_KEY_SIZE)
+               goto badkey;
+
+       memcpy(&ctx->key, key, keylen);
+
+       ctx->keylen = keylen;
+       ctx->enckeylen = enckeylen;
+       ctx->authkeylen = authkeylen;
+
+       return 0;
+
+badkey:
+       crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
+       return -EINVAL;
+}
+
+/*
+ * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @dma_len: length of dma mapped link_tbl space
+ * @dma_link_tbl: bus physical address of link_tbl
+ * @desc: h/w descriptor
+ * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1)
+ *
+ * if decrypting (with authcheck), or either one of src_nents or dst_nents
+ * is greater than 1, an integrity check value is concatenated to the end
+ * of link_tbl data
+ */
+struct ipsec_esp_edesc {
+       int src_nents;
+       int dst_nents;
+       int dma_len;
+       dma_addr_t dma_link_tbl;
+       struct talitos_desc desc;
+       struct talitos_ptr link_tbl[0];
+};
+
+static void ipsec_esp_unmap(struct device *dev,
+                           struct ipsec_esp_edesc *edesc,
+                           struct aead_request *areq)
+{
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[6], DMA_FROM_DEVICE);
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[3], DMA_TO_DEVICE);
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE);
+       unmap_single_talitos_ptr(dev, &edesc->desc.ptr[0], DMA_TO_DEVICE);
+
+       dma_unmap_sg(dev, areq->assoc, 1, DMA_TO_DEVICE);
+
+       if (areq->src != areq->dst) {
+               dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1,
+                            DMA_TO_DEVICE);
+               dma_unmap_sg(dev, areq->dst, edesc->dst_nents ? : 1,
+                            DMA_FROM_DEVICE);
+       } else {
+               dma_unmap_sg(dev, areq->src, edesc->src_nents ? : 1,
+                            DMA_BIDIRECTIONAL);
+       }
+
+       if (edesc->dma_len)
+               dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
+                                DMA_BIDIRECTIONAL);
+}
+
+/*
+ * ipsec_esp descriptor callbacks
+ */
+static void ipsec_esp_encrypt_done(struct device *dev,
+                                  struct talitos_desc *desc, void *context,
+                                  int err)
+{
+       struct aead_request *areq = context;
+       struct ipsec_esp_edesc *edesc =
+                container_of(desc, struct ipsec_esp_edesc, desc);
+       struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct scatterlist *sg;
+       void *icvdata;
+
+       ipsec_esp_unmap(dev, edesc, areq);
+
+       /* copy the generated ICV to dst */
+       if (edesc->dma_len) {
+               icvdata = &edesc->link_tbl[edesc->src_nents +
+                                          edesc->dst_nents + 1];
+               sg = sg_last(areq->dst, edesc->dst_nents);
+               memcpy((char *)sg_virt(sg) + sg->length - ctx->authsize,
+                      icvdata, ctx->authsize);
+       }
+
+       kfree(edesc);
+
+       aead_request_complete(areq, err);
+}
+
+static void ipsec_esp_decrypt_done(struct device *dev,
+                                  struct talitos_desc *desc, void *context,
+                                  int err)
+{
+       struct aead_request *req = context;
+       struct ipsec_esp_edesc *edesc =
+                container_of(desc, struct ipsec_esp_edesc, desc);
+       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct scatterlist *sg;
+       void *icvdata;
+
+       ipsec_esp_unmap(dev, edesc, req);
+
+       if (!err) {
+               /* auth check */
+               if (edesc->dma_len)
+                       icvdata = &edesc->link_tbl[edesc->src_nents +
+                                                  edesc->dst_nents + 1];
+               else
+                       icvdata = &edesc->link_tbl[0];
+
+               sg = sg_last(req->dst, edesc->dst_nents ? : 1);
+               err = memcmp(icvdata, (char *)sg_virt(sg) + sg->length -
+                            ctx->authsize, ctx->authsize) ? -EBADMSG : 0;
+       }
+
+       kfree(edesc);
+
+       aead_request_complete(req, err);
+}
+
+/*
+ * convert scatterlist to SEC h/w link table format
+ * stop at cryptlen bytes
+ */
+static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
+                          int cryptlen, struct talitos_ptr *link_tbl_ptr)
+{
+       int n_sg = sg_count;
+
+       while (n_sg--) {
+               link_tbl_ptr->ptr = cpu_to_be32(sg_dma_address(sg));
+               link_tbl_ptr->len = cpu_to_be16(sg_dma_len(sg));
+               link_tbl_ptr->j_extent = 0;
+               link_tbl_ptr++;
+               cryptlen -= sg_dma_len(sg);
+               sg = sg_next(sg);
+       }
+
+       /* adjust (decrease) last one (or two) entry's len to cryptlen */
+       link_tbl_ptr--;
+       while (link_tbl_ptr->len <= (-cryptlen)) {
+               /* Empty this entry, and move to previous one */
+               cryptlen += be16_to_cpu(link_tbl_ptr->len);
+               link_tbl_ptr->len = 0;
+               sg_count--;
+               link_tbl_ptr--;
+       }
+       link_tbl_ptr->len = cpu_to_be16(be16_to_cpu(link_tbl_ptr->len)
+                                       + cryptlen);
+
+       /* tag end of link table */
+       link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN;
+
+       return sg_count;
+}
+
+/*
+ * fill in and submit ipsec_esp descriptor
+ */
+static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
+                    u8 *giv, u64 seq,
+                    void (*callback) (struct device *dev,
+                                      struct talitos_desc *desc,
+                                      void *context, int error))
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_aead_ctx(aead);
+       struct device *dev = ctx->dev;
+       struct talitos_desc *desc = &edesc->desc;
+       unsigned int cryptlen = areq->cryptlen;
+       unsigned int authsize = ctx->authsize;
+       unsigned int ivsize;
+       int sg_count;
+
+       /* hmac key */
+       map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
+                              0, DMA_TO_DEVICE);
+       /* hmac data */
+       map_single_talitos_ptr(dev, &desc->ptr[1], sg_virt(areq->src) -
+                              sg_virt(areq->assoc), sg_virt(areq->assoc), 0,
+                              DMA_TO_DEVICE);
+       /* cipher iv */
+       ivsize = crypto_aead_ivsize(aead);
+       map_single_talitos_ptr(dev, &desc->ptr[2], ivsize, giv ?: areq->iv, 0,
+                              DMA_TO_DEVICE);
+
+       /* cipher key */
+       map_single_talitos_ptr(dev, &desc->ptr[3], ctx->enckeylen,
+                              (char *)&ctx->key + ctx->authkeylen, 0,
+                              DMA_TO_DEVICE);
+
+       /*
+        * cipher in
+        * map and adjust cipher len to aead request cryptlen.
+        * extent is bytes of HMAC postpended to ciphertext,
+        * typically 12 for ipsec
+        */
+       desc->ptr[4].len = cpu_to_be16(cryptlen);
+       desc->ptr[4].j_extent = authsize;
+
+       if (areq->src == areq->dst)
+               sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+                                     DMA_BIDIRECTIONAL);
+       else
+               sg_count = dma_map_sg(dev, areq->src, edesc->src_nents ? : 1,
+                                     DMA_TO_DEVICE);
+
+       if (sg_count == 1) {
+               desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
+       } else {
+               sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen,
+                                         &edesc->link_tbl[0]);
+               if (sg_count > 1) {
+                       desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
+                       desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl);
+                       dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
+                                                  edesc->dma_len, DMA_BIDIRECTIONAL);
+               } else {
+                       /* Only one segment now, so no link tbl needed */
+                       desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
+               }
+       }
+
+       /* cipher out */
+       desc->ptr[5].len = cpu_to_be16(cryptlen);
+       desc->ptr[5].j_extent = authsize;
+
+       if (areq->src != areq->dst) {
+               sg_count = dma_map_sg(dev, areq->dst, edesc->dst_nents ? : 1,
+                                     DMA_FROM_DEVICE);
+       }
+
+       if (sg_count == 1) {
+               desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst));
+       } else {
+               struct talitos_ptr *link_tbl_ptr =
+                       &edesc->link_tbl[edesc->src_nents];
+               struct scatterlist *sg;
+
+               desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *)
+                                              edesc->dma_link_tbl +
+                                              edesc->src_nents);
+               if (areq->src == areq->dst) {
+                       memcpy(link_tbl_ptr, &edesc->link_tbl[0],
+                              edesc->src_nents * sizeof(struct talitos_ptr));
+               } else {
+                       sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
+                                                 link_tbl_ptr);
+               }
+               link_tbl_ptr += sg_count - 1;
+
+               /* handle case where sg_last contains the ICV exclusively */
+               sg = sg_last(areq->dst, edesc->dst_nents);
+               if (sg->length == ctx->authsize)
+                       link_tbl_ptr--;
+
+               link_tbl_ptr->j_extent = 0;
+               link_tbl_ptr++;
+               link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN;
+               link_tbl_ptr->len = cpu_to_be16(authsize);
+
+               /* icv data follows link tables */
+               link_tbl_ptr->ptr = cpu_to_be32((struct talitos_ptr *)
+                                               edesc->dma_link_tbl +
+                                               edesc->src_nents +
+                                               edesc->dst_nents + 1);
+
+               desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP;
+               dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
+                                          edesc->dma_len, DMA_BIDIRECTIONAL);
+       }
+
+       /* iv out */
+       map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0,
+                              DMA_FROM_DEVICE);
+
+       return talitos_submit(dev, desc, callback, areq);
+}
+
+
+/*
+ * derive number of elements in scatterlist
+ */
+static int sg_count(struct scatterlist *sg_list, int nbytes)
+{
+       struct scatterlist *sg = sg_list;
+       int sg_nents = 0;
+
+       while (nbytes) {
+               sg_nents++;
+               nbytes -= sg->length;
+               sg = sg_next(sg);
+       }
+
+       return sg_nents;
+}
+
+/*
+ * allocate and map the ipsec_esp extended descriptor
+ */
+static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
+                                                    int icv_stashing)
+{
+       struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct ipsec_esp_edesc *edesc;
+       int src_nents, dst_nents, alloc_len, dma_len;
+
+       if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) {
+               dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize);
+       src_nents = (src_nents == 1) ? 0 : src_nents;
+
+       if (areq->dst == areq->src) {
+               dst_nents = src_nents;
+       } else {
+               dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize);
+               dst_nents = (dst_nents == 1) ? 0 : src_nents;
+       }
+
+       /*
+        * allocate space for base edesc plus the link tables,
+        * allowing for a separate entry for the generated ICV (+ 1),
+        * and the ICV data itself
+        */
+       alloc_len = sizeof(struct ipsec_esp_edesc);
+       if (src_nents || dst_nents) {
+               dma_len = (src_nents + dst_nents + 1) *
+                                sizeof(struct talitos_ptr) + ctx->authsize;
+               alloc_len += dma_len;
+       } else {
+               dma_len = 0;
+               alloc_len += icv_stashing ? ctx->authsize : 0;
+       }
+
+       edesc = kmalloc(alloc_len, GFP_DMA);
+       if (!edesc) {
+               dev_err(ctx->dev, "could not allocate edescriptor\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       edesc->src_nents = src_nents;
+       edesc->dst_nents = dst_nents;
+       edesc->dma_len = dma_len;
+       edesc->dma_link_tbl = dma_map_single(ctx->dev, &edesc->link_tbl[0],
+                                            edesc->dma_len, DMA_BIDIRECTIONAL);
+
+       return edesc;
+}
+
+static int aead_authenc_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct ipsec_esp_edesc *edesc;
+
+       /* allocate extended descriptor */
+       edesc = ipsec_esp_edesc_alloc(req, 0);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+
+       /* set encrypt */
+       edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
+
+       return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done);
+}
+
+static int aead_authenc_decrypt(struct aead_request *req)
+{
+       struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       unsigned int authsize = ctx->authsize;
+       struct ipsec_esp_edesc *edesc;
+       struct scatterlist *sg;
+       void *icvdata;
+
+       req->cryptlen -= authsize;
+
+       /* allocate extended descriptor */
+       edesc = ipsec_esp_edesc_alloc(req, 1);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+
+       /* stash incoming ICV for later cmp with ICV generated by the h/w */
+       if (edesc->dma_len)
+               icvdata = &edesc->link_tbl[edesc->src_nents +
+                                          edesc->dst_nents + 1];
+       else
+               icvdata = &edesc->link_tbl[0];
+
+       sg = sg_last(req->src, edesc->src_nents ? : 1);
+
+       memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
+              ctx->authsize);
+
+       /* decrypt */
+       edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
+
+       return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_done);
+}
+
+static int aead_authenc_givencrypt(
+       struct aead_givcrypt_request *req)
+{
+       struct aead_request *areq = &req->areq;
+       struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
+       struct ipsec_esp_edesc *edesc;
+
+       /* allocate extended descriptor */
+       edesc = ipsec_esp_edesc_alloc(areq, 0);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+
+       /* set encrypt */
+       edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
+
+       memcpy(req->giv, ctx->iv, crypto_aead_ivsize(authenc));
+
+       return ipsec_esp(edesc, areq, req->giv, req->seq,
+                        ipsec_esp_encrypt_done);
+}
+
+struct talitos_alg_template {
+       char name[CRYPTO_MAX_ALG_NAME];
+       char driver_name[CRYPTO_MAX_ALG_NAME];
+       unsigned int blocksize;
+       struct aead_alg aead;
+       struct device *dev;
+       __be32 desc_hdr_template;
+};
+
+static struct talitos_alg_template driver_algs[] = {
+       /* single-pass ipsec_esp descriptor */
+       {
+               .name = "authenc(hmac(sha1),cbc(aes))",
+               .driver_name = "authenc-hmac-sha1-cbc-aes-talitos",
+               .blocksize = AES_BLOCK_SIZE,
+               .aead = {
+                       .setkey = aead_authenc_setkey,
+                       .setauthsize = aead_authenc_setauthsize,
+                       .encrypt = aead_authenc_encrypt,
+                       .decrypt = aead_authenc_decrypt,
+                       .givencrypt = aead_authenc_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = AES_BLOCK_SIZE,
+                       .maxauthsize = SHA1_DIGEST_SIZE,
+                       },
+               .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
+                                    DESC_HDR_SEL0_AESU |
+                                    DESC_HDR_MODE0_AESU_CBC |
+                                    DESC_HDR_SEL1_MDEUA |
+                                    DESC_HDR_MODE1_MDEU_INIT |
+                                    DESC_HDR_MODE1_MDEU_PAD |
+                                    DESC_HDR_MODE1_MDEU_SHA1_HMAC,
+       },
+       {
+               .name = "authenc(hmac(sha1),cbc(des3_ede))",
+               .driver_name = "authenc-hmac-sha1-cbc-3des-talitos",
+               .blocksize = DES3_EDE_BLOCK_SIZE,
+               .aead = {
+                       .setkey = aead_authenc_setkey,
+                       .setauthsize = aead_authenc_setauthsize,
+                       .encrypt = aead_authenc_encrypt,
+                       .decrypt = aead_authenc_decrypt,
+                       .givencrypt = aead_authenc_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize = SHA1_DIGEST_SIZE,
+                       },
+               .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
+                                    DESC_HDR_SEL0_DEU |
+                                    DESC_HDR_MODE0_DEU_CBC |
+                                    DESC_HDR_MODE0_DEU_3DES |
+                                    DESC_HDR_SEL1_MDEUA |
+                                    DESC_HDR_MODE1_MDEU_INIT |
+                                    DESC_HDR_MODE1_MDEU_PAD |
+                                    DESC_HDR_MODE1_MDEU_SHA1_HMAC,
+       },
+       {
+               .name = "authenc(hmac(sha256),cbc(aes))",
+               .driver_name = "authenc-hmac-sha256-cbc-aes-talitos",
+               .blocksize = AES_BLOCK_SIZE,
+               .aead = {
+                       .setkey = aead_authenc_setkey,
+                       .setauthsize = aead_authenc_setauthsize,
+                       .encrypt = aead_authenc_encrypt,
+                       .decrypt = aead_authenc_decrypt,
+                       .givencrypt = aead_authenc_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = AES_BLOCK_SIZE,
+                       .maxauthsize = SHA256_DIGEST_SIZE,
+                       },
+               .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
+                                    DESC_HDR_SEL0_AESU |
+                                    DESC_HDR_MODE0_AESU_CBC |
+                                    DESC_HDR_SEL1_MDEUA |
+                                    DESC_HDR_MODE1_MDEU_INIT |
+                                    DESC_HDR_MODE1_MDEU_PAD |
+                                    DESC_HDR_MODE1_MDEU_SHA256_HMAC,
+       },
+       {
+               .name = "authenc(hmac(sha256),cbc(des3_ede))",
+               .driver_name = "authenc-hmac-sha256-cbc-3des-talitos",
+               .blocksize = DES3_EDE_BLOCK_SIZE,
+               .aead = {
+                       .setkey = aead_authenc_setkey,
+                       .setauthsize = aead_authenc_setauthsize,
+                       .encrypt = aead_authenc_encrypt,
+                       .decrypt = aead_authenc_decrypt,
+                       .givencrypt = aead_authenc_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize = SHA256_DIGEST_SIZE,
+                       },
+               .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
+                                    DESC_HDR_SEL0_DEU |
+                                    DESC_HDR_MODE0_DEU_CBC |
+                                    DESC_HDR_MODE0_DEU_3DES |
+                                    DESC_HDR_SEL1_MDEUA |
+                                    DESC_HDR_MODE1_MDEU_INIT |
+                                    DESC_HDR_MODE1_MDEU_PAD |
+                                    DESC_HDR_MODE1_MDEU_SHA256_HMAC,
+       },
+       {
+               .name = "authenc(hmac(md5),cbc(aes))",
+               .driver_name = "authenc-hmac-md5-cbc-aes-talitos",
+               .blocksize = AES_BLOCK_SIZE,
+               .aead = {
+                       .setkey = aead_authenc_setkey,
+                       .setauthsize = aead_authenc_setauthsize,
+                       .encrypt = aead_authenc_encrypt,
+                       .decrypt = aead_authenc_decrypt,
+                       .givencrypt = aead_authenc_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = AES_BLOCK_SIZE,
+                       .maxauthsize = MD5_DIGEST_SIZE,
+                       },
+               .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
+                                    DESC_HDR_SEL0_AESU |
+                                    DESC_HDR_MODE0_AESU_CBC |
+                                    DESC_HDR_SEL1_MDEUA |
+                                    DESC_HDR_MODE1_MDEU_INIT |
+                                    DESC_HDR_MODE1_MDEU_PAD |
+                                    DESC_HDR_MODE1_MDEU_MD5_HMAC,
+       },
+       {
+               .name = "authenc(hmac(md5),cbc(des3_ede))",
+               .driver_name = "authenc-hmac-md5-cbc-3des-talitos",
+               .blocksize = DES3_EDE_BLOCK_SIZE,
+               .aead = {
+                       .setkey = aead_authenc_setkey,
+                       .setauthsize = aead_authenc_setauthsize,
+                       .encrypt = aead_authenc_encrypt,
+                       .decrypt = aead_authenc_decrypt,
+                       .givencrypt = aead_authenc_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize = MD5_DIGEST_SIZE,
+                       },
+               .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP |
+                                    DESC_HDR_SEL0_DEU |
+                                    DESC_HDR_MODE0_DEU_CBC |
+                                    DESC_HDR_MODE0_DEU_3DES |
+                                    DESC_HDR_SEL1_MDEUA |
+                                    DESC_HDR_MODE1_MDEU_INIT |
+                                    DESC_HDR_MODE1_MDEU_PAD |
+                                    DESC_HDR_MODE1_MDEU_MD5_HMAC,
+       }
+};
+
+struct talitos_crypto_alg {
+       struct list_head entry;
+       struct device *dev;
+       __be32 desc_hdr_template;
+       struct crypto_alg crypto_alg;
+};
+
+static int talitos_cra_init(struct crypto_tfm *tfm)
+{
+       struct crypto_alg *alg = tfm->__crt_alg;
+       struct talitos_crypto_alg *talitos_alg =
+                container_of(alg, struct talitos_crypto_alg, crypto_alg);
+       struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       /* update context with ptr to dev */
+       ctx->dev = talitos_alg->dev;
+       /* copy descriptor header template value */
+       ctx->desc_hdr_template = talitos_alg->desc_hdr_template;
+
+       /* random first IV */
+       get_random_bytes(ctx->iv, TALITOS_MAX_IV_LENGTH);
+
+       return 0;
+}
+
+/*
+ * given the alg's descriptor header template, determine whether descriptor
+ * type and primary/secondary execution units required match the hw
+ * capabilities description provided in the device tree node.
+ */
+static int hw_supports(struct device *dev, __be32 desc_hdr_template)
+{
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = (1 << DESC_TYPE(desc_hdr_template) & priv->desc_types) &&
+             (1 << PRIMARY_EU(desc_hdr_template) & priv->exec_units);
+
+       if (SECONDARY_EU(desc_hdr_template))
+               ret = ret && (1 << SECONDARY_EU(desc_hdr_template)
+                             & priv->exec_units);
+
+       return ret;
+}
+
+static int __devexit talitos_remove(struct of_device *ofdev)
+{
+       struct device *dev = &ofdev->dev;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       struct talitos_crypto_alg *t_alg, *n;
+       int i;
+
+       list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) {
+               crypto_unregister_alg(&t_alg->crypto_alg);
+               list_del(&t_alg->entry);
+               kfree(t_alg);
+       }
+
+       if (hw_supports(dev, DESC_HDR_SEL0_RNG))
+               talitos_unregister_rng(dev);
+
+       kfree(priv->tail);
+       kfree(priv->head);
+
+       if (priv->fifo)
+               for (i = 0; i < priv->num_channels; i++)
+                       kfree(priv->fifo[i]);
+
+       kfree(priv->fifo);
+       kfree(priv->head_lock);
+       kfree(priv->tail_lock);
+
+       if (priv->irq != NO_IRQ) {
+               free_irq(priv->irq, dev);
+               irq_dispose_mapping(priv->irq);
+       }
+
+       tasklet_kill(&priv->done_task);
+       tasklet_kill(&priv->error_task);
+
+       iounmap(priv->reg);
+
+       dev_set_drvdata(dev, NULL);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
+                                                   struct talitos_alg_template
+                                                          *template)
+{
+       struct talitos_crypto_alg *t_alg;
+       struct crypto_alg *alg;
+
+       t_alg = kzalloc(sizeof(struct talitos_crypto_alg), GFP_KERNEL);
+       if (!t_alg)
+               return ERR_PTR(-ENOMEM);
+
+       alg = &t_alg->crypto_alg;
+
+       snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
+       snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+                template->driver_name);
+       alg->cra_module = THIS_MODULE;
+       alg->cra_init = talitos_cra_init;
+       alg->cra_priority = TALITOS_CRA_PRIORITY;
+       alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
+       alg->cra_blocksize = template->blocksize;
+       alg->cra_alignmask = 0;
+       alg->cra_type = &crypto_aead_type;
+       alg->cra_ctxsize = sizeof(struct talitos_ctx);
+       alg->cra_u.aead = template->aead;
+
+       t_alg->desc_hdr_template = template->desc_hdr_template;
+       t_alg->dev = dev;
+
+       return t_alg;
+}
+
+static int talitos_probe(struct of_device *ofdev,
+                        const struct of_device_id *match)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->node;
+       struct talitos_private *priv;
+       const unsigned int *prop;
+       int i, err;
+
+       priv = kzalloc(sizeof(struct talitos_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, priv);
+
+       priv->ofdev = ofdev;
+
+       tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);
+       tasklet_init(&priv->error_task, talitos_error, (unsigned long)dev);
+
+       priv->irq = irq_of_parse_and_map(np, 0);
+
+       if (priv->irq == NO_IRQ) {
+               dev_err(dev, "failed to map irq\n");
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       /* get the irq line */
+       err = request_irq(priv->irq, talitos_interrupt, 0,
+                         dev_driver_string(dev), dev);
+       if (err) {
+               dev_err(dev, "failed to request irq %d\n", priv->irq);
+               irq_dispose_mapping(priv->irq);
+               priv->irq = NO_IRQ;
+               goto err_out;
+       }
+
+       priv->reg = of_iomap(np, 0);
+       if (!priv->reg) {
+               dev_err(dev, "failed to of_iomap\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       /* get SEC version capabilities from device tree */
+       prop = of_get_property(np, "fsl,num-channels", NULL);
+       if (prop)
+               priv->num_channels = *prop;
+
+       prop = of_get_property(np, "fsl,channel-fifo-len", NULL);
+       if (prop)
+               priv->chfifo_len = *prop;
+
+       prop = of_get_property(np, "fsl,exec-units-mask", NULL);
+       if (prop)
+               priv->exec_units = *prop;
+
+       prop = of_get_property(np, "fsl,descriptor-types-mask", NULL);
+       if (prop)
+               priv->desc_types = *prop;
+
+       if (!is_power_of_2(priv->num_channels) || !priv->chfifo_len ||
+           !priv->exec_units || !priv->desc_types) {
+               dev_err(dev, "invalid property data in device tree node\n");
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       of_node_put(np);
+       np = NULL;
+
+       priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
+                                 GFP_KERNEL);
+       priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
+                                 GFP_KERNEL);
+       if (!priv->head_lock || !priv->tail_lock) {
+               dev_err(dev, "failed to allocate fifo locks\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       for (i = 0; i < priv->num_channels; i++) {
+               spin_lock_init(&priv->head_lock[i]);
+               spin_lock_init(&priv->tail_lock[i]);
+       }
+
+       priv->fifo = kmalloc(sizeof(struct talitos_request *) *
+                            priv->num_channels, GFP_KERNEL);
+       if (!priv->fifo) {
+               dev_err(dev, "failed to allocate request fifo\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       priv->fifo_len = roundup_pow_of_two(priv->chfifo_len);
+
+       for (i = 0; i < priv->num_channels; i++) {
+               priv->fifo[i] = kzalloc(sizeof(struct talitos_request) *
+                                       priv->fifo_len, GFP_KERNEL);
+               if (!priv->fifo[i]) {
+                       dev_err(dev, "failed to allocate request fifo %d\n", i);
+                       err = -ENOMEM;
+                       goto err_out;
+               }
+       }
+
+       priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
+       priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
+       if (!priv->head || !priv->tail) {
+               dev_err(dev, "failed to allocate request index space\n");
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       /* reset and initialize the h/w */
+       err = init_device(dev);
+       if (err) {
+               dev_err(dev, "failed to initialize device\n");
+               goto err_out;
+       }
+
+       /* register the RNG, if available */
+       if (hw_supports(dev, DESC_HDR_SEL0_RNG)) {
+               err = talitos_register_rng(dev);
+               if (err) {
+                       dev_err(dev, "failed to register hwrng: %d\n", err);
+                       goto err_out;
+               } else
+                       dev_info(dev, "hwrng\n");
+       }
+
+       /* register crypto algorithms the device supports */
+       INIT_LIST_HEAD(&priv->alg_list);
+
+       for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+               if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
+                       struct talitos_crypto_alg *t_alg;
+
+                       t_alg = talitos_alg_alloc(dev, &driver_algs[i]);
+                       if (IS_ERR(t_alg)) {
+                               err = PTR_ERR(t_alg);
+                               goto err_out;
+                       }
+
+                       err = crypto_register_alg(&t_alg->crypto_alg);
+                       if (err) {
+                               dev_err(dev, "%s alg registration failed\n",
+                                       t_alg->crypto_alg.cra_driver_name);
+                               kfree(t_alg);
+                       } else {
+                               list_add_tail(&t_alg->entry, &priv->alg_list);
+                               dev_info(dev, "%s\n",
+                                        t_alg->crypto_alg.cra_driver_name);
+                       }
+               }
+       }
+
+       return 0;
+
+err_out:
+       talitos_remove(ofdev);
+       if (np)
+               of_node_put(np);
+
+       return err;
+}
+
+static struct of_device_id talitos_match[] = {
+       {
+               .compatible = "fsl,sec2.0",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, talitos_match);
+
+static struct of_platform_driver talitos_driver = {
+       .name = "talitos",
+       .match_table = talitos_match,
+       .probe = talitos_probe,
+       .remove = __devexit_p(talitos_remove),
+};
+
+static int __init talitos_init(void)
+{
+       return of_register_platform_driver(&talitos_driver);
+}
+module_init(talitos_init);
+
+static void __exit talitos_exit(void)
+{
+       of_unregister_platform_driver(&talitos_driver);
+}
+module_exit(talitos_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kim Phillips <kim.phillips@freescale.com>");
+MODULE_DESCRIPTION("Freescale integrated security engine (SEC) driver");
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
new file mode 100644 (file)
index 0000000..c48a405
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Freescale SEC (talitos) device register and descriptor header defines
+ *
+ * Copyright (c) 2006-2008 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * TALITOS_xxx_LO addresses point to the low data bits (32-63) of the register
+ */
+
+/* global register offset addresses */
+#define TALITOS_MCR                    0x1030  /* master control register */
+#define TALITOS_MCR_LO                 0x1038
+#define   TALITOS_MCR_SWR              0x1     /* s/w reset */
+#define TALITOS_IMR                    0x1008  /* interrupt mask register */
+#define   TALITOS_IMR_INIT             0x10fff /* enable channel IRQs */
+#define TALITOS_IMR_LO                 0x100C
+#define   TALITOS_IMR_LO_INIT          0x20000 /* allow RNGU error IRQs */
+#define TALITOS_ISR                    0x1010  /* interrupt status register */
+#define   TALITOS_ISR_CHERR            0xaa    /* channel errors mask */
+#define   TALITOS_ISR_CHDONE           0x55    /* channel done mask */
+#define TALITOS_ISR_LO                 0x1014
+#define TALITOS_ICR                    0x1018  /* interrupt clear register */
+#define TALITOS_ICR_LO                 0x101C
+
+/* channel register address stride */
+#define TALITOS_CH_STRIDE              0x100
+
+/* channel configuration register  */
+#define TALITOS_CCCR(ch)               (ch * TALITOS_CH_STRIDE + 0x1108)
+#define   TALITOS_CCCR_CONT            0x2    /* channel continue */
+#define   TALITOS_CCCR_RESET           0x1    /* channel reset */
+#define TALITOS_CCCR_LO(ch)            (ch * TALITOS_CH_STRIDE + 0x110c)
+#define   TALITOS_CCCR_LO_CDWE         0x10   /* chan. done writeback enab. */
+#define   TALITOS_CCCR_LO_NT           0x4    /* notification type */
+#define   TALITOS_CCCR_LO_CDIE         0x2    /* channel done IRQ enable */
+
+/* CCPSR: channel pointer status register */
+#define TALITOS_CCPSR(ch)              (ch * TALITOS_CH_STRIDE + 0x1110)
+#define TALITOS_CCPSR_LO(ch)           (ch * TALITOS_CH_STRIDE + 0x1114)
+#define   TALITOS_CCPSR_LO_DOF         0x8000 /* double FF write oflow error */
+#define   TALITOS_CCPSR_LO_SOF         0x4000 /* single FF write oflow error */
+#define   TALITOS_CCPSR_LO_MDTE                0x2000 /* master data transfer error */
+#define   TALITOS_CCPSR_LO_SGDLZ       0x1000 /* s/g data len zero error */
+#define   TALITOS_CCPSR_LO_FPZ         0x0800 /* fetch ptr zero error */
+#define   TALITOS_CCPSR_LO_IDH         0x0400 /* illegal desc hdr error */
+#define   TALITOS_CCPSR_LO_IEU         0x0200 /* invalid EU error */
+#define   TALITOS_CCPSR_LO_EU          0x0100 /* EU error detected */
+#define   TALITOS_CCPSR_LO_GB          0x0080 /* gather boundary error */
+#define   TALITOS_CCPSR_LO_GRL         0x0040 /* gather return/length error */
+#define   TALITOS_CCPSR_LO_SB          0x0020 /* scatter boundary error */
+#define   TALITOS_CCPSR_LO_SRL         0x0010 /* scatter return/length error */
+
+/* channel fetch fifo register */
+#define TALITOS_FF(ch)                 (ch * TALITOS_CH_STRIDE + 0x1148)
+#define TALITOS_FF_LO(ch)              (ch * TALITOS_CH_STRIDE + 0x114c)
+
+/* current descriptor pointer register */
+#define TALITOS_CDPR(ch)               (ch * TALITOS_CH_STRIDE + 0x1140)
+#define TALITOS_CDPR_LO(ch)            (ch * TALITOS_CH_STRIDE + 0x1144)
+
+/* descriptor buffer register */
+#define TALITOS_DESCBUF(ch)            (ch * TALITOS_CH_STRIDE + 0x1180)
+#define TALITOS_DESCBUF_LO(ch)         (ch * TALITOS_CH_STRIDE + 0x1184)
+
+/* gather link table */
+#define TALITOS_GATHER(ch)             (ch * TALITOS_CH_STRIDE + 0x11c0)
+#define TALITOS_GATHER_LO(ch)          (ch * TALITOS_CH_STRIDE + 0x11c4)
+
+/* scatter link table */
+#define TALITOS_SCATTER(ch)            (ch * TALITOS_CH_STRIDE + 0x11e0)
+#define TALITOS_SCATTER_LO(ch)         (ch * TALITOS_CH_STRIDE + 0x11e4)
+
+/* execution unit interrupt status registers */
+#define TALITOS_DEUISR                 0x2030 /* DES unit */
+#define TALITOS_DEUISR_LO              0x2034
+#define TALITOS_AESUISR                        0x4030 /* AES unit */
+#define TALITOS_AESUISR_LO             0x4034
+#define TALITOS_MDEUISR                        0x6030 /* message digest unit */
+#define TALITOS_MDEUISR_LO             0x6034
+#define TALITOS_AFEUISR                        0x8030 /* arc4 unit */
+#define TALITOS_AFEUISR_LO             0x8034
+#define TALITOS_RNGUISR                        0xa030 /* random number unit */
+#define TALITOS_RNGUISR_LO             0xa034
+#define TALITOS_RNGUSR                 0xa028 /* rng status */
+#define TALITOS_RNGUSR_LO              0xa02c
+#define   TALITOS_RNGUSR_LO_RD         0x1     /* reset done */
+#define   TALITOS_RNGUSR_LO_OFL                0xff0000/* output FIFO length */
+#define TALITOS_RNGUDSR                        0xa010  /* data size */
+#define TALITOS_RNGUDSR_LO             0xa014
+#define TALITOS_RNGU_FIFO              0xa800  /* output FIFO */
+#define TALITOS_RNGU_FIFO_LO           0xa804  /* output FIFO */
+#define TALITOS_RNGURCR                        0xa018  /* reset control */
+#define TALITOS_RNGURCR_LO             0xa01c
+#define   TALITOS_RNGURCR_LO_SR                0x1     /* software reset */
+#define TALITOS_PKEUISR                        0xc030 /* public key unit */
+#define TALITOS_PKEUISR_LO             0xc034
+#define TALITOS_KEUISR                 0xe030 /* kasumi unit */
+#define TALITOS_KEUISR_LO              0xe034
+#define TALITOS_CRCUISR                        0xf030 /* cyclic redundancy check unit*/
+#define TALITOS_CRCUISR_LO             0xf034
+
+/*
+ * talitos descriptor header (hdr) bits
+ */
+
+/* written back when done */
+#define DESC_HDR_DONE                  __constant_cpu_to_be32(0xff000000)
+
+/* primary execution unit select */
+#define        DESC_HDR_SEL0_MASK              __constant_cpu_to_be32(0xf0000000)
+#define        DESC_HDR_SEL0_AFEU              __constant_cpu_to_be32(0x10000000)
+#define        DESC_HDR_SEL0_DEU               __constant_cpu_to_be32(0x20000000)
+#define        DESC_HDR_SEL0_MDEUA             __constant_cpu_to_be32(0x30000000)
+#define        DESC_HDR_SEL0_MDEUB             __constant_cpu_to_be32(0xb0000000)
+#define        DESC_HDR_SEL0_RNG               __constant_cpu_to_be32(0x40000000)
+#define        DESC_HDR_SEL0_PKEU              __constant_cpu_to_be32(0x50000000)
+#define        DESC_HDR_SEL0_AESU              __constant_cpu_to_be32(0x60000000)
+#define        DESC_HDR_SEL0_KEU               __constant_cpu_to_be32(0x70000000)
+#define        DESC_HDR_SEL0_CRCU              __constant_cpu_to_be32(0x80000000)
+
+/* primary execution unit mode (MODE0) and derivatives */
+#define        DESC_HDR_MODE0_ENCRYPT          __constant_cpu_to_be32(0x00100000)
+#define        DESC_HDR_MODE0_AESU_CBC         __constant_cpu_to_be32(0x00200000)
+#define        DESC_HDR_MODE0_DEU_CBC          __constant_cpu_to_be32(0x00400000)
+#define        DESC_HDR_MODE0_DEU_3DES         __constant_cpu_to_be32(0x00200000)
+#define        DESC_HDR_MODE0_MDEU_INIT        __constant_cpu_to_be32(0x01000000)
+#define        DESC_HDR_MODE0_MDEU_HMAC        __constant_cpu_to_be32(0x00800000)
+#define        DESC_HDR_MODE0_MDEU_PAD         __constant_cpu_to_be32(0x00400000)
+#define        DESC_HDR_MODE0_MDEU_MD5         __constant_cpu_to_be32(0x00200000)
+#define        DESC_HDR_MODE0_MDEU_SHA256      __constant_cpu_to_be32(0x00100000)
+#define        DESC_HDR_MODE0_MDEU_SHA1        __constant_cpu_to_be32(0x00000000)
+#define        DESC_HDR_MODE0_MDEU_MD5_HMAC    (DESC_HDR_MODE0_MDEU_MD5 | \
+                                        DESC_HDR_MODE0_MDEU_HMAC)
+#define        DESC_HDR_MODE0_MDEU_SHA256_HMAC (DESC_HDR_MODE0_MDEU_SHA256 | \
+                                        DESC_HDR_MODE0_MDEU_HMAC)
+#define        DESC_HDR_MODE0_MDEU_SHA1_HMAC   (DESC_HDR_MODE0_MDEU_SHA1 | \
+                                        DESC_HDR_MODE0_MDEU_HMAC)
+
+/* secondary execution unit select (SEL1) */
+#define        DESC_HDR_SEL1_MASK              __constant_cpu_to_be32(0x000f0000)
+#define        DESC_HDR_SEL1_MDEUA             __constant_cpu_to_be32(0x00030000)
+#define        DESC_HDR_SEL1_MDEUB             __constant_cpu_to_be32(0x000b0000)
+#define        DESC_HDR_SEL1_CRCU              __constant_cpu_to_be32(0x00080000)
+
+/* secondary execution unit mode (MODE1) and derivatives */
+#define        DESC_HDR_MODE1_MDEU_INIT        __constant_cpu_to_be32(0x00001000)
+#define        DESC_HDR_MODE1_MDEU_HMAC        __constant_cpu_to_be32(0x00000800)
+#define        DESC_HDR_MODE1_MDEU_PAD         __constant_cpu_to_be32(0x00000400)
+#define        DESC_HDR_MODE1_MDEU_MD5         __constant_cpu_to_be32(0x00000200)
+#define        DESC_HDR_MODE1_MDEU_SHA256      __constant_cpu_to_be32(0x00000100)
+#define        DESC_HDR_MODE1_MDEU_SHA1        __constant_cpu_to_be32(0x00000000)
+#define        DESC_HDR_MODE1_MDEU_MD5_HMAC    (DESC_HDR_MODE1_MDEU_MD5 | \
+                                        DESC_HDR_MODE1_MDEU_HMAC)
+#define        DESC_HDR_MODE1_MDEU_SHA256_HMAC (DESC_HDR_MODE1_MDEU_SHA256 | \
+                                        DESC_HDR_MODE1_MDEU_HMAC)
+#define        DESC_HDR_MODE1_MDEU_SHA1_HMAC   (DESC_HDR_MODE1_MDEU_SHA1 | \
+                                        DESC_HDR_MODE1_MDEU_HMAC)
+
+/* direction of overall data flow (DIR) */
+#define        DESC_HDR_DIR_INBOUND            __constant_cpu_to_be32(0x00000002)
+
+/* request done notification (DN) */
+#define        DESC_HDR_DONE_NOTIFY            __constant_cpu_to_be32(0x00000001)
+
+/* descriptor types */
+#define DESC_HDR_TYPE_AESU_CTR_NONSNOOP                __constant_cpu_to_be32(0 << 3)
+#define DESC_HDR_TYPE_IPSEC_ESP                        __constant_cpu_to_be32(1 << 3)
+#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU  __constant_cpu_to_be32(2 << 3)
+#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU       __constant_cpu_to_be32(4 << 3)
+
+/* link table extent field bits */
+#define DESC_PTR_LNKTBL_JUMP                   0x80
+#define DESC_PTR_LNKTBL_RETURN                 0x02
+#define DESC_PTR_LNKTBL_NEXT                   0x01
index dc2cec6127d1816982558de72a2ee9e4c1b884a5..ebb9e51deb0cd86acb38ea5b0180d7c1b16a862a 100644 (file)
@@ -26,6 +26,16 @@ config EDD_OFF
          kernel. Say N if you want EDD enabled by default. EDD can be dynamically set
          using the kernel parameter 'edd={on|skipmbr|off}'.
 
+config FIRMWARE_MEMMAP
+    bool "Add firmware-provided memory map to sysfs" if EMBEDDED
+    default (X86_64 || X86_32)
+    help
+      Add the firmware-provided (unmodified) memory map to /sys/firmware/memmap.
+      That memory map is used for example by kexec to set up parameter area
+      for the next kernel, but can also be used for debugging purposes.
+
+      See also Documentation/ABI/testing/sysfs-firmware-memmap.
+
 config EFI_VARS
        tristate "EFI Variable Support via sysfs"
        depends on EFI
index 4c9147154df891d0659cd1f68582a9f6fca4a196..1c3c17343dbeabb730d0bbc6313f7dca7ca1b364 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_DCDBAS)          += dcdbas.o
 obj-$(CONFIG_DMIID)            += dmi-id.o
 obj-$(CONFIG_ISCSI_IBFT_FIND)  += iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)       += iscsi_ibft.o
+obj-$(CONFIG_FIRMWARE_MEMMAP)  += memmap.o
index c5e3ed7e903b3a14f405554f8c6163f2d62cb998..455575be3560d2336c75d2cc8aaf42c64a728f9c 100644 (file)
@@ -8,6 +8,11 @@
 #include <linux/slab.h>
 #include <asm/dmi.h>
 
+/*
+ * DMI stands for "Desktop Management Interface".  It is part
+ * of and an antecedent to, SMBIOS, which stands for System
+ * Management BIOS.  See further: http://www.dmtf.org/standards
+ */
 static char dmi_empty_string[] = "        ";
 
 static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
new file mode 100644 (file)
index 0000000..e23399c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * linux/drivers/firmware/memmap.c
+ *  Copyright (C) 2008 SUSE LINUX Products GmbH
+ *  by Bernhard Walle <bwalle@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 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.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/firmware-map.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+
+/*
+ * Data types ------------------------------------------------------------------
+ */
+
+/*
+ * Firmware map entry. Because firmware memory maps are flat and not
+ * hierarchical, it's ok to organise them in a linked list. No parent
+ * information is necessary as for the resource tree.
+ */
+struct firmware_map_entry {
+       resource_size_t         start;  /* start of the memory range */
+       resource_size_t         end;    /* end of the memory range (incl.) */
+       const char              *type;  /* type of the memory range */
+       struct list_head        list;   /* entry for the linked list */
+       struct kobject          kobj;   /* kobject for each entry */
+};
+
+/*
+ * Forward declarations --------------------------------------------------------
+ */
+static ssize_t memmap_attr_show(struct kobject *kobj,
+                               struct attribute *attr, char *buf);
+static ssize_t start_show(struct firmware_map_entry *entry, char *buf);
+static ssize_t end_show(struct firmware_map_entry *entry, char *buf);
+static ssize_t type_show(struct firmware_map_entry *entry, char *buf);
+
+/*
+ * Static data -----------------------------------------------------------------
+ */
+
+struct memmap_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct firmware_map_entry *entry, char *buf);
+};
+
+struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
+struct memmap_attribute memmap_end_attr   = __ATTR_RO(end);
+struct memmap_attribute memmap_type_attr  = __ATTR_RO(type);
+
+/*
+ * These are default attributes that are added for every memmap entry.
+ */
+static struct attribute *def_attrs[] = {
+       &memmap_start_attr.attr,
+       &memmap_end_attr.attr,
+       &memmap_type_attr.attr,
+       NULL
+};
+
+static struct sysfs_ops memmap_attr_ops = {
+       .show = memmap_attr_show,
+};
+
+static struct kobj_type memmap_ktype = {
+       .sysfs_ops      = &memmap_attr_ops,
+       .default_attrs  = def_attrs,
+};
+
+/*
+ * Registration functions ------------------------------------------------------
+ */
+
+/*
+ * Firmware memory map entries
+ */
+static LIST_HEAD(map_entries);
+
+/**
+ * Common implementation of firmware_map_add() and firmware_map_add_early()
+ * which expects a pre-allocated struct firmware_map_entry.
+ *
+ * @start: Start of the memory range.
+ * @end:   End of the memory range (inclusive).
+ * @type:  Type of the memory range.
+ * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised
+ *         entry.
+ */
+static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
+                                 const char *type,
+                                 struct firmware_map_entry *entry)
+{
+       BUG_ON(start > end);
+
+       entry->start = start;
+       entry->end = end;
+       entry->type = type;
+       INIT_LIST_HEAD(&entry->list);
+       kobject_init(&entry->kobj, &memmap_ktype);
+
+       list_add_tail(&entry->list, &map_entries);
+
+       return 0;
+}
+
+/*
+ * See <linux/firmware-map.h> for documentation.
+ */
+int firmware_map_add(resource_size_t start, resource_size_t end,
+                    const char *type)
+{
+       struct firmware_map_entry *entry;
+
+       entry = kmalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
+       WARN_ON(!entry);
+       if (!entry)
+               return -ENOMEM;
+
+       return firmware_map_add_entry(start, end, type, entry);
+}
+
+/*
+ * See <linux/firmware-map.h> for documentation.
+ */
+int __init firmware_map_add_early(resource_size_t start, resource_size_t end,
+                                 const char *type)
+{
+       struct firmware_map_entry *entry;
+
+       entry = alloc_bootmem_low(sizeof(struct firmware_map_entry));
+       WARN_ON(!entry);
+       if (!entry)
+               return -ENOMEM;
+
+       return firmware_map_add_entry(start, end, type, entry);
+}
+
+/*
+ * Sysfs functions -------------------------------------------------------------
+ */
+
+static ssize_t start_show(struct firmware_map_entry *entry, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->start);
+}
+
+static ssize_t end_show(struct firmware_map_entry *entry, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->end);
+}
+
+static ssize_t type_show(struct firmware_map_entry *entry, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
+}
+
+#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
+#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
+
+static ssize_t memmap_attr_show(struct kobject *kobj,
+                               struct attribute *attr, char *buf)
+{
+       struct firmware_map_entry *entry = to_memmap_entry(kobj);
+       struct memmap_attribute *memmap_attr = to_memmap_attr(attr);
+
+       return memmap_attr->show(entry, buf);
+}
+
+/*
+ * Initialises stuff and adds the entries in the map_entries list to
+ * sysfs. Important is that firmware_map_add() and firmware_map_add_early()
+ * must be called before late_initcall.
+ */
+static int __init memmap_init(void)
+{
+       int i = 0;
+       struct firmware_map_entry *entry;
+       struct kset *memmap_kset;
+
+       memmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
+       WARN_ON(!memmap_kset);
+       if (!memmap_kset)
+               return -ENOMEM;
+
+       list_for_each_entry(entry, &map_entries, list) {
+               entry->kobj.kset = memmap_kset;
+               kobject_add(&entry->kobj, NULL, "%d", i++);
+       }
+
+       return 0;
+}
+late_initcall(memmap_init);
+
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
new file mode 100644 (file)
index 0000000..de566cf
--- /dev/null
@@ -0,0 +1 @@
+obj-y                  += drm/
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
new file mode 100644 (file)
index 0000000..e9f9a97
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+
+drm-y       := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
+               drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
+               drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
+               drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
+               drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
+
+drm-$(CONFIG_COMPAT) += drm_ioc32.o
+
+obj-$(CONFIG_DRM)      += drm.o
+obj-$(CONFIG_DRM_TDFX) += tdfx/
+obj-$(CONFIG_DRM_R128) += r128/
+obj-$(CONFIG_DRM_RADEON)+= radeon/
+obj-$(CONFIG_DRM_MGA)  += mga/
+obj-$(CONFIG_DRM_I810) += i810/
+obj-$(CONFIG_DRM_I830) += i830/
+obj-$(CONFIG_DRM_I915)  += i915/
+obj-$(CONFIG_DRM_SIS)   += sis/
+obj-$(CONFIG_DRM_SAVAGE)+= savage/
+obj-$(CONFIG_DRM_VIA)  +=via/
+
diff --git a/drivers/gpu/drm/i810/Makefile b/drivers/gpu/drm/i810/Makefile
new file mode 100644 (file)
index 0000000..43844ec
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+i810-y := i810_drv.o i810_dma.o
+
+obj-$(CONFIG_DRM_I810) += i810.o
diff --git a/drivers/gpu/drm/i830/Makefile b/drivers/gpu/drm/i830/Makefile
new file mode 100644 (file)
index 0000000..c642ee0
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+i830-y := i830_drv.o i830_dma.o i830_irq.o
+
+obj-$(CONFIG_DRM_I830) += i830.o
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
new file mode 100644 (file)
index 0000000..a9e6046
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
+
+i915-$(CONFIG_COMPAT)   += i915_ioc32.o
+
+obj-$(CONFIG_DRM_I915)  += i915.o
diff --git a/drivers/gpu/drm/mga/Makefile b/drivers/gpu/drm/mga/Makefile
new file mode 100644 (file)
index 0000000..6068478
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+mga-y := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
+
+mga-$(CONFIG_COMPAT) += mga_ioc32.o
+
+obj-$(CONFIG_DRM_MGA)  += mga.o
+
diff --git a/drivers/gpu/drm/r128/Makefile b/drivers/gpu/drm/r128/Makefile
new file mode 100644 (file)
index 0000000..1cc72ae
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+r128-y   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
+
+r128-$(CONFIG_COMPAT)   += r128_ioc32.o
+
+obj-$(CONFIG_DRM_R128) += r128.o
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
new file mode 100644 (file)
index 0000000..feb521e
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
+
+radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
+
+obj-$(CONFIG_DRM_RADEON)+= radeon.o
diff --git a/drivers/gpu/drm/savage/Makefile b/drivers/gpu/drm/savage/Makefile
new file mode 100644 (file)
index 0000000..d8f84ac
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y = -Iinclude/drm
+savage-y := savage_drv.o savage_bci.o savage_state.o
+
+obj-$(CONFIG_DRM_SAVAGE)+= savage.o
+
diff --git a/drivers/gpu/drm/sis/Makefile b/drivers/gpu/drm/sis/Makefile
new file mode 100644 (file)
index 0000000..441c061
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y = -Iinclude/drm
+sis-y := sis_drv.o sis_mm.o
+
+obj-$(CONFIG_DRM_SIS)   += sis.o
+
+
diff --git a/drivers/gpu/drm/tdfx/Makefile b/drivers/gpu/drm/tdfx/Makefile
new file mode 100644 (file)
index 0000000..0379f29
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+tdfx-y := tdfx_drv.o
+
+obj-$(CONFIG_DRM_TDFX) += tdfx.o
diff --git a/drivers/gpu/drm/via/Makefile b/drivers/gpu/drm/via/Makefile
new file mode 100644 (file)
index 0000000..d59e258
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+via-y    := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
+
+obj-$(CONFIG_DRM_VIA)  +=via.o
index 3381424d70a195ed70bb3525e0160d96c18af033..8dbf4d9b6447cdd6e6bf2add89382b1f55ec0213 100644 (file)
@@ -63,11 +63,11 @@ MODULE_LICENSE("Dual MPL/GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
 
-#ifdef PCMCIA_DEBUG
-INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#ifdef CONFIG_PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, 0);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";
+/*static char *version =
+"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";*/
 #else
 #define DEBUG(n, args...)
 #endif
@@ -375,7 +375,7 @@ failed:
 
 ======================================================================*/
 
-void ide_release(struct pcmcia_device *link)
+static void ide_release(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
     ide_hwif_t *hwif = info->hwif;
index 0f47f4697cdf4f97f1b591e2677c40f070cfccf7..9ce3b3baf3a20b3cac63695bbe327048cab4b246 100644 (file)
@@ -66,6 +66,9 @@ static irqreturn_t input_handler(int rq, void *dev_id)
                case XENKBD_TYPE_MOTION:
                        input_report_rel(dev, REL_X, event->motion.rel_x);
                        input_report_rel(dev, REL_Y, event->motion.rel_y);
+                       if (event->motion.rel_z)
+                               input_report_rel(dev, REL_WHEEL,
+                                                -event->motion.rel_z);
                        break;
                case XENKBD_TYPE_KEY:
                        dev = NULL;
@@ -84,6 +87,9 @@ static irqreturn_t input_handler(int rq, void *dev_id)
                case XENKBD_TYPE_POS:
                        input_report_abs(dev, ABS_X, event->pos.abs_x);
                        input_report_abs(dev, ABS_Y, event->pos.abs_y);
+                       if (event->pos.rel_z)
+                               input_report_rel(dev, REL_WHEEL,
+                                                -event->pos.rel_z);
                        break;
                }
                if (dev)
@@ -152,7 +158,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev,
        ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
        for (i = BTN_LEFT; i <= BTN_TASK; i++)
                set_bit(i, ptr->keybit);
-       ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
        input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
        input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
 
@@ -294,6 +300,16 @@ InitWait:
                 */
                if (dev->state != XenbusStateConnected)
                        goto InitWait; /* no InitWait seen yet, fudge it */
+
+               /* Set input abs params to match backend screen res */
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "width", "%d", &val) > 0)
+                       input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
+
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "height", "%d", &val) > 0)
+                       input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
+
                break;
 
        case XenbusStateClosing:
@@ -337,4 +353,6 @@ static void __exit xenkbd_cleanup(void)
 module_init(xenkbd_init);
 module_exit(xenkbd_cleanup);
 
+MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vkbd");
index 6b8dbb9ba73bbedf67aa06d756dfc94d2a66d663..76f2b36881c3b43871533399cc242b4dfd24cd43 100644 (file)
@@ -1,6 +1,6 @@
 config LGUEST
        tristate "Linux hypervisor example code"
-       depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX && !(X86_VISWS || X86_VOYAGER)
+       depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX && !X86_VOYAGER
        select HVC_DRIVER
        ---help---
          This is a very simple module which allows you to run
index 005bd045d2ebca47a61a5633bfa171fe9df29896..5faefeaf679057b9c6b3e029dee4544343e5c132 100644 (file)
@@ -136,7 +136,6 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
  * first step in the migration to the kernel types.  pte_pfn is already defined
  * in the kernel. */
 #define pgd_flags(x)   (pgd_val(x) & ~PAGE_MASK)
-#define pte_flags(x)   (pte_val(x) & ~PAGE_MASK)
 #define pgd_pfn(x)     (pgd_val(x) >> PAGE_SHIFT)
 
 /* interrupts_and_traps.c: */
index 10748240cb2fde2bd8942dbb19e300cc6c32961c..6a866d7c8ae5885e3a0f75970106b1e76efca652 100644 (file)
@@ -50,17 +50,19 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector)
 /**
  *     linear_mergeable_bvec -- tell bio layer if two requests can be merged
  *     @q: request queue
- *     @bio: the buffer head that's been built up so far
+ *     @bvm: properties of new bio
  *     @biovec: the request that could be merged to it.
  *
  *     Return amount of bytes we can take at this offset
  */
-static int linear_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
+static int linear_mergeable_bvec(struct request_queue *q,
+                                struct bvec_merge_data *bvm,
+                                struct bio_vec *biovec)
 {
        mddev_t *mddev = q->queuedata;
        dev_info_t *dev0;
-       unsigned long maxsectors, bio_sectors = bio->bi_size >> 9;
-       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9;
+       sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
 
        dev0 = which_dev(mddev, sector);
        maxsectors = (dev0->size << 1) - (sector - (dev0->offset<<1));
index 914c04ddec7c64690cdb24a4b77c83172d4d38ab..bcbb82594a193c275dd4db15fadc46fd4a6494d6 100644 (file)
@@ -241,18 +241,20 @@ static int create_strip_zones (mddev_t *mddev)
 /**
  *     raid0_mergeable_bvec -- tell bio layer if a two requests can be merged
  *     @q: request queue
- *     @bio: the buffer head that's been built up so far
+ *     @bvm: properties of new bio
  *     @biovec: the request that could be merged to it.
  *
  *     Return amount of bytes we can accept at this offset
  */
-static int raid0_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
+static int raid0_mergeable_bvec(struct request_queue *q,
+                               struct bvec_merge_data *bvm,
+                               struct bio_vec *biovec)
 {
        mddev_t *mddev = q->queuedata;
-       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
        int max;
        unsigned int chunk_sectors = mddev->chunk_size >> 9;
-       unsigned int bio_sectors = bio->bi_size >> 9;
+       unsigned int bio_sectors = bvm->bi_size >> 9;
 
        max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
        if (max < 0) max = 0; /* bio_add cannot handle a negative return */
index a71277b640ab036bea60206e29900c034ddd50a3..22bb2b1b886d96887948f25fd8efbc199b3b3079 100644 (file)
@@ -439,26 +439,27 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
 /**
  *     raid10_mergeable_bvec -- tell bio layer if a two requests can be merged
  *     @q: request queue
- *     @bio: the buffer head that's been built up so far
+ *     @bvm: properties of new bio
  *     @biovec: the request that could be merged to it.
  *
  *     Return amount of bytes we can accept at this offset
  *      If near_copies == raid_disk, there are no striping issues,
  *      but in that case, the function isn't called at all.
  */
-static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio,
-                               struct bio_vec *bio_vec)
+static int raid10_mergeable_bvec(struct request_queue *q,
+                                struct bvec_merge_data *bvm,
+                                struct bio_vec *biovec)
 {
        mddev_t *mddev = q->queuedata;
-       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
        int max;
        unsigned int chunk_sectors = mddev->chunk_size >> 9;
-       unsigned int bio_sectors = bio->bi_size >> 9;
+       unsigned int bio_sectors = bvm->bi_size >> 9;
 
        max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
        if (max < 0) max = 0; /* bio_add cannot handle a negative return */
-       if (max <= bio_vec->bv_len && bio_sectors == 0)
-               return bio_vec->bv_len;
+       if (max <= biovec->bv_len && bio_sectors == 0)
+               return biovec->bv_len;
        else
                return max;
 }
index 3b27df52456b510219c4f3f22dfb2c644ff3845c..9ce7154845c67eb4acffc441462667b9a152f468 100644 (file)
@@ -3314,15 +3314,17 @@ static int raid5_congested(void *data, int bits)
 /* We want read requests to align with chunks where possible,
  * but write requests don't need to.
  */
-static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
+static int raid5_mergeable_bvec(struct request_queue *q,
+                               struct bvec_merge_data *bvm,
+                               struct bio_vec *biovec)
 {
        mddev_t *mddev = q->queuedata;
-       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
        int max;
        unsigned int chunk_sectors = mddev->chunk_size >> 9;
-       unsigned int bio_sectors = bio->bi_size >> 9;
+       unsigned int bio_sectors = bvm->bi_size >> 9;
 
-       if (bio_data_dir(bio) == WRITE)
+       if ((bvm->bi_rw & 1) == WRITE)
                return biovec->bv_len; /* always allow writes to be mergeable */
 
        max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
index 0d5ce03cdff24cf5d683a3750bb2a56ba397b6e1..5b5a14dab3d38d5e77a26381f849d2e26822934c 100644 (file)
@@ -332,7 +332,7 @@ static int __init pwm_probe(struct platform_device *pdev)
        p->base = ioremap(r->start, r->end - r->start + 1);
        if (!p->base)
                goto fail;
-       p->clk = clk_get(&pdev->dev, "mck");
+       p->clk = clk_get(&pdev->dev, "pwm_clk");
        if (IS_ERR(p->clk)) {
                status = PTR_ERR(p->clk);
                p->clk = NULL;
index 4a79b187b568870ad207eaa94e905aec5133e390..5c29872184e65b64c3f5938968aaeb29061601f6 100644 (file)
@@ -130,10 +130,6 @@ typedef struct partition_t {
     u_int16_t          DataUnits;
     u_int32_t          BlocksPerUnit;
     erase_unit_header_t        header;
-#if 0
-    region_info_t      region;
-    memory_handle_t    handle;
-#endif
 } partition_t;
 
 /* Partition state flags */
index 1912d968718b38e81752b8c5df587b9081ef92f7..0cc31675aeb909c472479c41a14abc970ec9217e 100644 (file)
@@ -498,17 +498,14 @@ static int pcmciamtd_config(struct pcmcia_device *link)
        int i;
        config_info_t t;
        static char *probes[] = { "jedec_probe", "cfi_probe" };
-       cisinfo_t cisinfo;
        int new_name = 0;
 
        DEBUG(3, "link=0x%p", link);
 
        DEBUG(2, "Validating CIS");
-       ret = pcmcia_validate_cis(link, &cisinfo);
+       ret = pcmcia_validate_cis(link, NULL);
        if(ret != CS_SUCCESS) {
                cs_error(link, GetTupleData, ret);
-       } else {
-               DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
        }
 
        card_settings(dev, link, &new_name);
@@ -563,9 +560,7 @@ static int pcmciamtd_config(struct pcmcia_device *link)
        DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
 
        /* Get write protect status */
-       CS_CHECK(GetStatus, pcmcia_get_status(link, &status));
-       DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
-             status.CardState, (unsigned long)link->win);
+       DEBUG(2, "window handle = 0x%8.8lx", (unsigned long)link->win);
        dev->win_base = ioremap(req.Base, req.Size);
        if(!dev->win_base) {
                err("ioremap(%lu, %u) failed", req.Base, req.Size);
index 92dccd43bdcab39fbd0bcd374d3447a33961443c..0a5745a854c7bbbe562a5f4e7b88e464a8891b0d 100644 (file)
@@ -1277,8 +1277,45 @@ static int __exit macb_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int macb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *netdev = platform_get_drvdata(pdev);
+       struct macb *bp = netdev_priv(netdev);
+
+       netif_device_detach(netdev);
+
+#ifndef CONFIG_ARCH_AT91
+       clk_disable(bp->hclk);
+#endif
+       clk_disable(bp->pclk);
+
+       return 0;
+}
+
+static int macb_resume(struct platform_device *pdev)
+{
+       struct net_device *netdev = platform_get_drvdata(pdev);
+       struct macb *bp = netdev_priv(netdev);
+
+       clk_enable(bp->pclk);
+#ifndef CONFIG_ARCH_AT91
+       clk_enable(bp->hclk);
+#endif
+
+       netif_device_attach(netdev);
+
+       return 0;
+}
+#else
+#define macb_suspend   NULL
+#define macb_resume    NULL
+#endif
+
 static struct platform_driver macb_driver = {
        .remove         = __exit_p(macb_remove),
+       .suspend        = macb_suspend,
+       .resume         = macb_resume,
        .driver         = {
                .name           = "macb",
                .owner  = THIS_MODULE,
index d26f69b0184f05bac7ec906d5d4f50c11b99b458..ef671d1a3bf08441719b5f0bda8338648b1d1ee6 100644 (file)
@@ -1324,7 +1324,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
                goto fail;
        }
 
-       txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+       txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
        if (!txs) {
                err = -ENOMEM;
                xenbus_dev_fatal(dev, err, "allocating tx ring page");
@@ -1340,7 +1340,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
        }
 
        info->tx_ring_ref = err;
-       rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+       rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
        if (!rxs) {
                err = -ENOMEM;
                xenbus_dev_fatal(dev, err, "allocating rx ring page");
index 66c0fd21894b155e9db690b65a86bfddffca29c4..bb0642318a959453e9ef0c68190070ac7d9290a4 100644 (file)
@@ -1637,12 +1637,43 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
 }
 
 #ifdef CONFIG_DMAR_GFX_WA
-extern int arch_get_ram_range(int slot, u64 *addr, u64 *size);
+struct iommu_prepare_data {
+       struct pci_dev *pdev;
+       int ret;
+};
+
+static int __init iommu_prepare_work_fn(unsigned long start_pfn,
+                                        unsigned long end_pfn, void *datax)
+{
+       struct iommu_prepare_data *data;
+
+       data = (struct iommu_prepare_data *)datax;
+
+       data->ret = iommu_prepare_identity_map(data->pdev,
+                               start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
+       return data->ret;
+
+}
+
+static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
+{
+       int nid;
+       struct iommu_prepare_data data;
+
+       data.pdev = pdev;
+       data.ret = 0;
+
+       for_each_online_node(nid) {
+               work_with_active_regions(nid, iommu_prepare_work_fn, &data);
+               if (data.ret)
+                       return data.ret;
+       }
+       return data.ret;
+}
+
 static void __init iommu_prepare_gfx_mapping(void)
 {
        struct pci_dev *pdev = NULL;
-       u64 base, size;
-       int slot;
        int ret;
 
        for_each_pci_dev(pdev) {
@@ -1651,17 +1682,9 @@ static void __init iommu_prepare_gfx_mapping(void)
                        continue;
                printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
                        pci_name(pdev));
-               slot = arch_get_ram_range(0, &base, &size);
-               while (slot >= 0) {
-                       ret = iommu_prepare_identity_map(pdev,
-                                       base, base + size);
-                       if (ret)
-                               goto error;
-                       slot = arch_get_ram_range(slot, &base, &size);
-               }
-               continue;
-error:
-               printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
+               ret = iommu_prepare_with_active_regions(pdev);
+               if (ret)
+                       printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
        }
 }
 #endif
index 1b0eb5aaf650738a57300890941136d33ec06c62..e45402adac3f89e233ae1a4ebbcf6e0619e4d2dd 100644 (file)
@@ -263,6 +263,13 @@ config OMAP_CF
          Say Y here to support the CompactFlash controller on OMAP.
          Note that this doesn't support "True IDE" mode.
 
+config BFIN_CFPCMCIA
+       tristate "Blackfin CompactFlash PCMCIA Driver"
+       depends on PCMCIA && BLACKFIN
+       help
+         Say Y here to support the CompactFlash PCMCIA driver for Blackfin.
+
+
 config AT91_CF
        tristate "AT91 CompactFlash Controller"
        depends on PCMCIA && ARCH_AT91RM9200
index 6f6478ba7174fa8291eee50bb8a671ff913672bc..85c6cc931f979760dd3c545762b1dbd6b4a198a1 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_PCMCIA_AU1X00)                   += au1x00_ss.o
 obj-$(CONFIG_PCMCIA_VRC4171)                   += vrc4171_card.o
 obj-$(CONFIG_PCMCIA_VRC4173)                   += vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)                          += omap_cf.o
+obj-$(CONFIG_BFIN_CFPCMCIA)                    += bfin_cf_pcmcia.o
 obj-$(CONFIG_AT91_CF)                          += at91_cf.o
 obj-$(CONFIG_ELECTRA_CF)                       += electra_cf.o
 
index 1e467bb54077fed1f5f92175ba240d251e6a256d..a53ef5902518d88e7434b456a4d5b54eb0f90663 100644 (file)
@@ -26,7 +26,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
@@ -34,9 +33,9 @@
 #define AU1000_PCMCIA_IO_SPEED       (255)
 #define AU1000_PCMCIA_MEM_SPEED      (300)
 
-#define AU1X_SOCK0_IO        0xF00000000
-#define AU1X_SOCK0_PHYS_ATTR 0xF40000000
-#define AU1X_SOCK0_PHYS_MEM  0xF80000000
+#define AU1X_SOCK0_IO        0xF00000000ULL
+#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL
+#define AU1X_SOCK0_PHYS_MEM  0xF80000000ULL
 /* pseudo 32 bit phys addresses, which get fixed up to the
  * real 36 bit address in fixup_bigphys_addr() */
 #define AU1X_SOCK0_PSEUDO_PHYS_ATTR 0xF4000000
 /* pcmcia socket 1 needs external glue logic so the memory map
  * differs from board to board.
  */
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_PB1200)
-#define AU1X_SOCK1_IO        0xF08000000
-#define AU1X_SOCK1_PHYS_ATTR 0xF48000000
-#define AU1X_SOCK1_PHYS_MEM  0xF88000000
+#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || \
+    defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || \
+    defined(CONFIG_MIPS_PB1200)
+#define AU1X_SOCK1_IO        0xF08000000ULL
+#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL
+#define AU1X_SOCK1_PHYS_MEM  0xF88000000ULL
 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000
 #define AU1X_SOCK1_PSEUDO_PHYS_MEM  0xF8800000
-#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_DB1200)
-#define AU1X_SOCK1_IO        0xF04000000
-#define AU1X_SOCK1_PHYS_ATTR 0xF44000000
-#define AU1X_SOCK1_PHYS_MEM  0xF84000000
+#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
+      defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || \
+      defined(CONFIG_MIPS_DB1200)
+#define AU1X_SOCK1_IO        0xF04000000ULL
+#define AU1X_SOCK1_PHYS_ATTR 0xF44000000ULL
+#define AU1X_SOCK1_PHYS_MEM  0xF84000000ULL
 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000
 #define AU1X_SOCK1_PSEUDO_PHYS_MEM  0xF8400000
 #endif
index 157e41423a0a5390e42bb5106eccc5be489fb16f..aa1cd4d3aa292c4e840a4b09471b6068a81f9385 100644 (file)
@@ -35,7 +35,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/bus_ops.h>
 #include "cs_internal.h"
index c78ed53475107c7371b503aa68c6d6ff96c6c4e6..8a9b18cee847e980881c1f0536925fca0bbcc52f 100644 (file)
@@ -39,7 +39,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/bus_ops.h>
 #include "cs_internal.h"
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c
new file mode 100644 (file)
index 0000000..bb73388
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * file: drivers/pcmcia/bfin_cf.c
+ *
+ * based on: drivers/pcmcia/omap_cf.c
+ * omap_cf.c -- OMAP 16xx CompactFlash controller driver
+ *
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006-2008 Michael Hennerich Analog Devices Inc.
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose.  see the
+ * gnu general public license for more details.
+ *
+ * you should have received a copy of the gnu general public license
+ * along with this program; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cisreg.h>
+#include <asm/gpio.h>
+
+#define        SZ_1K   0x00000400
+#define        SZ_8K   0x00002000
+#define        SZ_2K   (2 * SZ_1K)
+
+#define        POLL_INTERVAL   (2 * HZ)
+
+#define        CF_ATASEL_ENA   0x20311802      /* Inverts RESET */
+#define        CF_ATASEL_DIS   0x20311800
+
+#define bfin_cf_present(pfx) (gpio_get_value(pfx))
+
+/*--------------------------------------------------------------------------*/
+
+static const char driver_name[] = "bfin_cf_pcmcia";
+
+struct bfin_cf_socket {
+       struct pcmcia_socket socket;
+
+       struct timer_list timer;
+       unsigned present:1;
+       unsigned active:1;
+
+       struct platform_device *pdev;
+       unsigned long phys_cf_io;
+       unsigned long phys_cf_attr;
+       u_int irq;
+       u_short cd_pfx;
+};
+
+/*--------------------------------------------------------------------------*/
+static int bfin_cf_reset(void)
+{
+       outw(0, CF_ATASEL_ENA);
+       mdelay(200);
+       outw(0, CF_ATASEL_DIS);
+
+       return 0;
+}
+
+static int bfin_cf_ss_init(struct pcmcia_socket *s)
+{
+       return 0;
+}
+
+/* the timer is primarily to kick this socket's pccardd */
+static void bfin_cf_timer(unsigned long _cf)
+{
+       struct bfin_cf_socket *cf = (void *)_cf;
+       unsigned short present = bfin_cf_present(cf->cd_pfx);
+
+       if (present != cf->present) {
+               cf->present = present;
+               dev_dbg(&cf->pdev->dev, ": card %s\n",
+                        present ? "present" : "gone");
+               pcmcia_parse_events(&cf->socket, SS_DETECT);
+       }
+
+       if (cf->active)
+               mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+}
+
+static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+       struct bfin_cf_socket *cf;
+
+       if (!sp)
+               return -EINVAL;
+
+       cf = container_of(s, struct bfin_cf_socket, socket);
+
+       if (bfin_cf_present(cf->cd_pfx)) {
+               *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
+               s->irq.AssignedIRQ = 0;
+               s->pci_irq = cf->irq;
+
+       } else
+               *sp = 0;
+       return 0;
+}
+
+static int
+bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
+{
+
+       struct bfin_cf_socket *cf;
+       cf = container_of(sock, struct bfin_cf_socket, socket);
+
+       switch (s->Vcc) {
+       case 0:
+       case 33:
+               break;
+       case 50:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (s->flags & SS_RESET) {
+               disable_irq(cf->irq);
+               bfin_cf_reset();
+               enable_irq(cf->irq);
+       }
+
+       dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n",
+                s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+       return 0;
+}
+
+static int bfin_cf_ss_suspend(struct pcmcia_socket *s)
+{
+       return bfin_cf_set_socket(s, &dead_socket);
+}
+
+/* regions are 2K each:  mem, attrib, io (and reserved-for-ide) */
+
+static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+       struct bfin_cf_socket *cf;
+
+       cf = container_of(s, struct bfin_cf_socket, socket);
+       io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
+       io->start = cf->phys_cf_io;
+       io->stop = io->start + SZ_2K - 1;
+       return 0;
+}
+
+static int
+bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
+{
+       struct bfin_cf_socket *cf;
+
+       if (map->card_start)
+               return -EINVAL;
+       cf = container_of(s, struct bfin_cf_socket, socket);
+       map->static_start = cf->phys_cf_io;
+       map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
+       if (map->flags & MAP_ATTRIB)
+               map->static_start = cf->phys_cf_attr;
+
+       return 0;
+}
+
+static struct pccard_operations bfin_cf_ops = {
+       .init = bfin_cf_ss_init,
+       .suspend = bfin_cf_ss_suspend,
+       .get_status = bfin_cf_get_status,
+       .set_socket = bfin_cf_set_socket,
+       .set_io_map = bfin_cf_set_io_map,
+       .set_mem_map = bfin_cf_set_mem_map,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __devinit bfin_cf_probe(struct platform_device *pdev)
+{
+       struct bfin_cf_socket *cf;
+       struct resource *io_mem, *attr_mem;
+       int irq;
+       unsigned short cd_pfx;
+       int status = 0;
+
+       dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -EINVAL;
+
+       cd_pfx = platform_get_irq(pdev, 1);     /*Card Detect GPIO PIN */
+
+       if (gpio_request(cd_pfx, "pcmcia: CD")) {
+               dev_err(&pdev->dev,
+                      "Failed ro request Card Detect GPIO_%d\n",
+                      cd_pfx);
+               return -EBUSY;
+       }
+       gpio_direction_input(cd_pfx);
+
+       cf = kzalloc(sizeof *cf, GFP_KERNEL);
+       if (!cf) {
+               gpio_free(cd_pfx);
+               return -ENOMEM;
+       }
+
+       cf->cd_pfx = cd_pfx;
+
+       setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf);
+
+       cf->pdev = pdev;
+       platform_set_drvdata(pdev, cf);
+
+       cf->irq = irq;
+       cf->socket.pci_irq = irq;
+
+       set_irq_type(irq, IRQF_TRIGGER_LOW);
+
+       io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+       if (!io_mem || !attr_mem)
+               goto fail0;
+
+       cf->phys_cf_io = io_mem->start;
+       cf->phys_cf_attr = attr_mem->start;
+
+       /* pcmcia layer only remaps "real" memory */
+       cf->socket.io_offset = (unsigned long)
+           ioremap(cf->phys_cf_io, SZ_2K);
+
+       if (!cf->socket.io_offset)
+               goto fail0;
+
+       dev_err(&pdev->dev, ": on irq %d\n", irq);
+
+       dev_dbg(&pdev->dev, ": %s\n",
+                bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)");
+
+       cf->socket.owner = THIS_MODULE;
+       cf->socket.dev.parent = &pdev->dev;
+       cf->socket.ops = &bfin_cf_ops;
+       cf->socket.resource_ops = &pccard_static_ops;
+       cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
+           | SS_CAP_MEM_ALIGN;
+       cf->socket.map_size = SZ_2K;
+
+       status = pcmcia_register_socket(&cf->socket);
+       if (status < 0)
+               goto fail2;
+
+       cf->active = 1;
+       mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+       return 0;
+
+fail2:
+       iounmap((void __iomem *)cf->socket.io_offset);
+       release_mem_region(cf->phys_cf_io, SZ_8K);
+
+fail0:
+       gpio_free(cf->cd_pfx);
+       kfree(cf);
+       platform_set_drvdata(pdev, NULL);
+
+       return status;
+}
+
+static int __devexit bfin_cf_remove(struct platform_device *pdev)
+{
+       struct bfin_cf_socket *cf = platform_get_drvdata(pdev);
+
+       gpio_free(cf->cd_pfx);
+       cf->active = 0;
+       pcmcia_unregister_socket(&cf->socket);
+       del_timer_sync(&cf->timer);
+       iounmap((void __iomem *)cf->socket.io_offset);
+       release_mem_region(cf->phys_cf_io, SZ_8K);
+       platform_set_drvdata(pdev, NULL);
+       kfree(cf);
+       return 0;
+}
+
+static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return pcmcia_socket_dev_suspend(&pdev->dev, mesg);
+}
+
+static int bfin_cf_resume(struct platform_device *pdev)
+{
+       return pcmcia_socket_dev_resume(&pdev->dev);
+}
+
+static struct platform_driver bfin_cf_driver = {
+       .driver = {
+                  .name = (char *)driver_name,
+                  .owner = THIS_MODULE,
+                  },
+       .probe = bfin_cf_probe,
+       .remove = __devexit_p(bfin_cf_remove),
+       .suspend = bfin_cf_suspend,
+       .resume = bfin_cf_resume,
+};
+
+static int __init bfin_cf_init(void)
+{
+       return platform_driver_register(&bfin_cf_driver);
+}
+
+static void __exit bfin_cf_exit(void)
+{
+       platform_driver_unregister(&bfin_cf_driver);
+}
+
+module_init(bfin_cf_init);
+module_exit(bfin_cf_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>")
+MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
+MODULE_LICENSE("GPL");
index fb2f38dc92c560de378ddab5b688657e82d8661a..911ca0e8dfc29b94498fec85b10c73cb33be7aef 100644 (file)
 #include <asm/irq.h>
 #include <asm/io.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
index 36379535f9daf17f8cb86a779cab491203afa9c1..9fcff0c336193e3fa4d5ccfc465e5766514cd4cc 100644 (file)
@@ -30,7 +30,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
@@ -1439,10 +1438,11 @@ EXPORT_SYMBOL(pccard_read_tuple);
     
 ======================================================================*/
 
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info)
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *info)
 {
     tuple_t *tuple;
     cisparse_t *p;
+    unsigned int count = 0;
     int ret, reserved, dev_ok = 0, ident_ok = 0;
 
     if (!s)
@@ -1457,7 +1457,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_
        return CS_OUT_OF_RESOURCE;
     }
 
-    info->Chains = reserved = 0;
+    count = reserved = 0;
     tuple->DesiredTuple = RETURN_FIRST_TUPLE;
     tuple->Attributes = TUPLE_RETURN_COMMON;
     ret = pccard_get_first_tuple(s, function, tuple);
@@ -1482,7 +1482,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_
     if (!dev_ok && !ident_ok)
        goto done;
 
-    for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
+    for (count = 1; count < MAX_TUPLES; count++) {
        ret = pccard_get_next_tuple(s, function, tuple);
        if (ret != CS_SUCCESS) break;
        if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
@@ -1490,11 +1490,13 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_
            ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
            reserved++;
     }
-    if ((info->Chains == MAX_TUPLES) || (reserved > 5) ||
-       ((!dev_ok || !ident_ok) && (info->Chains > 10)))
-       info->Chains = 0;
+    if ((count) || (reserved > 5) ||
+       ((!dev_ok || !ident_ok) && (count > 10)))
+       count = 0;
 
 done:
+    if (info)
+           *info = count;
     kfree(tuple);
     kfree(p);
     return CS_SUCCESS;
index 29276bd28295007212a73e89c4bc44cb6f0a0a2a..d1207393fc3e4029a8b5f6402f82c185d517ff39 100644 (file)
 #include <asm/system.h>
 #include <asm/irq.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -238,7 +236,6 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
 
        init_completion(&socket->socket_released);
        init_completion(&socket->thread_done);
-       init_waitqueue_head(&socket->thread_wait);
        mutex_init(&socket->skt_mutex);
        spin_lock_init(&socket->thread_lock);
 
@@ -278,10 +275,9 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
 
        cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops);
 
-       if (socket->thread) {
-               wake_up(&socket->thread_wait);
+       if (socket->thread)
                kthread_stop(socket->thread);
-       }
+
        release_cis_mem(socket);
 
        /* remove from our own list */
@@ -635,7 +631,6 @@ static void socket_detect_change(struct pcmcia_socket *skt)
 static int pccardd(void *__skt)
 {
        struct pcmcia_socket *skt = __skt;
-       DECLARE_WAITQUEUE(wait, current);
        int ret;
 
        skt->thread = current;
@@ -656,7 +651,6 @@ static int pccardd(void *__skt)
        if (ret)
                dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
 
-       add_wait_queue(&skt->thread_wait, &wait);
        complete(&skt->thread_done);
 
        set_freezable();
@@ -694,8 +688,6 @@ static int pccardd(void *__skt)
        /* make sure we are running before we exit */
        set_current_state(TASK_RUNNING);
 
-       remove_wait_queue(&skt->thread_wait, &wait);
-
        /* remove from the device core */
        pccard_sysfs_remove_socket(&skt->dev);
        device_unregister(&skt->dev);
@@ -716,7 +708,7 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
                s->thread_events |= events;
                spin_unlock_irqrestore(&s->thread_lock, flags);
 
-               wake_up(&s->thread_wait);
+               wake_up_process(s->thread);
        }
 } /* pcmcia_parse_events */
 EXPORT_SYMBOL(pcmcia_parse_events);
index e7d5d141f24dc9b661f9ed4412752c53a04b7764..63dc1a28bda2772d6f2f213656ce07223cd8dd6c 100644 (file)
 #define CLIENT_WIN_REQ(i)      (0x1<<(i))
 #define CLIENT_CARDBUS         0x8000
 
-#define REGION_MAGIC   0xE3C9
-typedef struct region_t {
-    u_short            region_magic;
-    u_short            state;
-    dev_info_t         dev_info;
-    struct pcmcia_device       *mtd;
-    u_int              MediaID;
-    region_info_t      info;
-} region_t;
-
-#define REGION_STALE   0x01
-
 /* Each card function gets one of these guys */
 typedef struct config_t {
        struct kref     ref;
@@ -130,7 +118,6 @@ extern struct list_head pcmcia_socket_list;
 int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req);
 int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config);
 int pccard_reset_card(struct pcmcia_socket *skt);
-int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status);
 
 
 struct pcmcia_callback{
index e40775443d04c73233735c61b0802eaa4936a751..4174d9656e357f8ec5f16520ad03c86544a5e969 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kref.h>
 #include <linux/dma-mapping.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -741,9 +740,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
 
 static int pcmcia_card_add(struct pcmcia_socket *s)
 {
-       cisinfo_t cisinfo;
        cistpl_longlink_mfc_t mfc;
-       unsigned int no_funcs, i;
+       unsigned int no_funcs, i, no_chains;
        int ret = 0;
 
        if (!(s->resource_setup_done)) {
@@ -757,8 +755,8 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
                return -EAGAIN; /* try again, but later... */
        }
 
-       ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
-       if (ret || !cisinfo.Chains) {
+       ret = pccard_validate_cis(s, BIND_FN_ALL, &no_chains);
+       if (ret || !no_chains) {
                ds_dbg(0, "invalid CIS or invalid resources\n");
                return -ENODEV;
        }
@@ -852,7 +850,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
        struct pcmcia_socket *s = dev->socket;
        const struct firmware *fw;
-       char path[20];
+       char path[FIRMWARE_NAME_MAX];
        int ret = -ENOMEM;
        int no_funcs;
        int old_funcs;
@@ -864,7 +862,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 
        ds_dbg(1, "trying to load CIS file %s\n", filename);
 
-       if (strlen(filename) > 14) {
+       if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) {
                printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n",
                        filename);
                return -EINVAL;
index f2e810f53c81ca67b172e7b4789b60d9b2d3b473..fb2bc1fb015d417c19d879378a4538bee57ee372 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $
- *
  * Device driver for the PCMCIA controller module of the
  * Hitachi HD64465 handheld companion chip.
  *
@@ -48,7 +46,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
 #include "cs_internal.h"
 
 #define MODNAME "hd64465_ss"
index e13618656ff7ee7807618c9a52e0398334e04505..46561face128842e4a3bd8c7c3138e36a59d7fc9 100644 (file)
@@ -5,8 +5,6 @@
  *
  * Author: Arjan Van De Ven <arjanv@redhat.com>
  * Loosly based on i82365.c from the pcmcia-cs package
- *
- * $Id: i82092aa.c,v 1.2 2001/10/23 14:43:34 arjanv Exp $
  */
 
 #include <linux/kernel.h>
index b0d453303c5deb852e917af9e2757ba1b10edfbb..8836d393ad020ce58894745b490b2d6b1199e68c 100644 (file)
@@ -3,8 +3,6 @@
 
 #include <linux/interrupt.h>
 
-/* $Id: i82092aa.h,v 1.1.1.1 2001/09/19 14:53:15 dwmw2 Exp $ */
-
 /* Debuging defines */
 #ifdef NOTRACE
 #define enter(x)   printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)
index 32a2ab119798ccfc2f18c1df52377b7da2009ad3..68f6b2702bc42c66f27758c3fbbd25dcb80f83bc 100644 (file)
@@ -1263,7 +1263,7 @@ static int __init init_i82365(void)
 
     ret = driver_register(&i82365_driver);
     if (ret)
-       return ret;
+       goto err_out;
 
     i82365_device = platform_device_alloc("i82365", 0);
     if (i82365_device) {
@@ -1273,10 +1273,8 @@ static int __init init_i82365(void)
     } else
            ret = -ENOMEM;
 
-    if (ret) {
-       driver_unregister(&i82365_driver);
-       return ret;
-    }
+    if (ret)
+       goto err_driver_unregister;
 
     printk(KERN_INFO "Intel ISA PCIC probe: ");
     sockets = 0;
@@ -1285,16 +1283,17 @@ static int __init init_i82365(void)
 
     if (sockets == 0) {
        printk("not found.\n");
-       platform_device_unregister(i82365_device);
-       release_region(i365_base, 2);
-       driver_unregister(&i82365_driver);
-       return -ENODEV;
+       ret = -ENODEV;
+       goto err_dev_unregister;
     }
 
     /* Set up interrupt handler(s) */
     if (grab_irq != 0)
-       request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
-    
+       ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
+
+    if (ret)
+       goto err_socket_release;
+
     /* register sockets with the pcmcia core */
     for (i = 0; i < sockets; i++) {
            socket[i].socket.dev.parent = &i82365_device->dev;
@@ -1324,7 +1323,23 @@ static int __init init_i82365(void)
     }
     
     return 0;
-    
+err_socket_release:
+    for (i = 0; i < sockets; i++) {
+       /* Turn off all interrupt sources! */
+       i365_set(i, I365_CSCINT, 0);
+       release_region(socket[i].ioaddr, 2);
+    }
+err_dev_unregister:
+    platform_device_unregister(i82365_device);
+    release_region(i365_base, 2);
+#ifdef CONFIG_PNP
+    if (i82365_pnpdev)
+       pnp_disable_dev(i82365_pnpdev);
+#endif
+err_driver_unregister:
+    driver_unregister(&i82365_driver);
+err_out:
+    return ret;
 } /* init_i82365 */
 
 static void __exit exit_i82365(void)
index ac70d2cb7dd409764deb755e13e821d366702d5f..13a5fbd50a078fe3d45c2c1028066e679fe7c581 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series.
  *
- * (C) 1999-2000 Magnus Damm <damm@bitsmart.com>
+ * (C) 1999-2000 Magnus Damm <damm@opensource.se>
  * (C) 2001-2002 Montavista Software, Inc.
  *     <mlocke@mvista.com>
  *
@@ -60,7 +60,6 @@
 #include <asm/of_device.h>
 #include <asm/of_platform.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
index 5f186abca1082843a7b12e30865b3bb7c8b83f34..afd00e7bbbefe92f53cbfd82cc52ea8f323357e8 100644 (file)
 #include <linux/pci.h>
 #include <linux/workqueue.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
 
@@ -138,6 +138,154 @@ static int proc_read_drivers(char *buf, char **start, off_t pos,
 }
 #endif
 
+
+#ifdef CONFIG_PCMCIA_PROBE
+
+static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
+{
+       int irq;
+       u32 mask;
+
+       irq = adj->resource.irq.IRQ;
+       if ((irq < 0) || (irq > 15))
+               return CS_BAD_IRQ;
+
+       if (adj->Action != REMOVE_MANAGED_RESOURCE)
+               return 0;
+
+       mask = 1 << irq;
+
+       if (!(s->irq_mask & mask))
+               return 0;
+
+       s->irq_mask &= ~mask;
+
+       return 0;
+}
+
+#else
+
+static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
+       return CS_SUCCESS;
+}
+
+#endif
+
+static int pcmcia_adjust_resource_info(adjust_t *adj)
+{
+       struct pcmcia_socket *s;
+       int ret = CS_UNSUPPORTED_FUNCTION;
+       unsigned long flags;
+
+       down_read(&pcmcia_socket_list_rwsem);
+       list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
+
+               if (adj->Resource == RES_IRQ)
+                       ret = adjust_irq(s, adj);
+
+               else if (s->resource_ops->add_io) {
+                       unsigned long begin, end;
+
+                       /* you can't use the old interface if the new
+                        * one was used before */
+                       spin_lock_irqsave(&s->lock, flags);
+                       if ((s->resource_setup_new) &&
+                           !(s->resource_setup_old)) {
+                               spin_unlock_irqrestore(&s->lock, flags);
+                               continue;
+                       } else if (!(s->resource_setup_old))
+                               s->resource_setup_old = 1;
+                       spin_unlock_irqrestore(&s->lock, flags);
+
+                       switch (adj->Resource) {
+                       case RES_MEMORY_RANGE:
+                               begin = adj->resource.memory.Base;
+                               end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
+                               if (s->resource_ops->add_mem)
+                                       ret =s->resource_ops->add_mem(s, adj->Action, begin, end);
+                       case RES_IO_RANGE:
+                               begin = adj->resource.io.BasePort;
+                               end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
+                               if (s->resource_ops->add_io)
+                                       ret = s->resource_ops->add_io(s, adj->Action, begin, end);
+                       }
+                       if (!ret) {
+                               /* as there's no way we know this is the
+                                * last call to adjust_resource_info, we
+                                * always need to assume this is the latest
+                                * one... */
+                               spin_lock_irqsave(&s->lock, flags);
+                               s->resource_setup_done = 1;
+                               spin_unlock_irqrestore(&s->lock, flags);
+                       }
+               }
+       }
+       up_read(&pcmcia_socket_list_rwsem);
+
+       return (ret);
+}
+
+/** pccard_get_status
+ *
+ * Get the current socket state bits.  We don't support the latched
+ * SocketState yet: I haven't seen any point for it.
+ */
+
+static int pccard_get_status(struct pcmcia_socket *s,
+                            struct pcmcia_device *p_dev,
+                            cs_status_t *status)
+{
+       config_t *c;
+       int val;
+
+       s->ops->get_status(s, &val);
+       status->CardState = status->SocketState = 0;
+       status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+       status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+       status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+       status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+       if (s->state & SOCKET_SUSPEND)
+               status->CardState |= CS_EVENT_PM_SUSPEND;
+       if (!(s->state & SOCKET_PRESENT))
+               return CS_NO_CARD;
+
+       c = (p_dev) ? p_dev->function_config : NULL;
+
+       if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+           (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
+               u_char reg;
+               if (c->CardValues & PRESENT_PIN_REPLACE) {
+                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
+                       status->CardState |=
+                               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+                       status->CardState |=
+                               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+                       status->CardState |=
+                               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+                       status->CardState |=
+                               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+               } else {
+                       /* No PRR?  Then assume we're always ready */
+                       status->CardState |= CS_EVENT_READY_CHANGE;
+               }
+               if (c->CardValues & PRESENT_EXT_STATUS) {
+                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
+                       status->CardState |=
+                               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+               }
+               return CS_SUCCESS;
+       }
+       status->CardState |=
+               (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+       status->CardState |=
+               (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+       status->CardState |=
+               (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+       status->CardState |=
+               (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+       return CS_SUCCESS;
+} /* pccard_get_status */
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -546,8 +694,6 @@ static u_int ds_poll(struct file *file, poll_table *wait)
 
 /*====================================================================*/
 
-extern int pcmcia_adjust_resource_info(adjust_t *adj);
-
 static int ds_ioctl(struct inode * inode, struct file * file,
                    u_int cmd, u_long arg)
 {
@@ -649,7 +795,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
        mutex_lock(&s->skt_mutex);
        pcmcia_validate_mem(s);
        mutex_unlock(&s->skt_mutex);
-       ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
+       ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains);
        break;
     case DS_SUSPEND_CARD:
        ret = pcmcia_suspend_card(s);
index 1d128fbd1a92d9f4dcdaed4a3065c3365b5fce68..4884a18cf9e69918c0e3371cebb5a89b944921bb 100644 (file)
 #include <linux/pci.h>
 #include <linux/device.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -311,74 +309,6 @@ int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
 EXPORT_SYMBOL(pcmcia_get_window);
 
 
-/** pccard_get_status
- *
- * Get the current socket state bits.  We don't support the latched
- * SocketState yet: I haven't seen any point for it.
- */
-
-int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev,
-                     cs_status_t *status)
-{
-       config_t *c;
-       int val;
-
-       s->ops->get_status(s, &val);
-       status->CardState = status->SocketState = 0;
-       status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
-       status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
-       status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
-       status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
-       if (s->state & SOCKET_SUSPEND)
-               status->CardState |= CS_EVENT_PM_SUSPEND;
-       if (!(s->state & SOCKET_PRESENT))
-               return CS_NO_CARD;
-
-       c = (p_dev) ? p_dev->function_config : NULL;
-
-       if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
-           (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
-               u_char reg;
-               if (c->CardValues & PRESENT_PIN_REPLACE) {
-                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
-                       status->CardState |=
-                               (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
-                       status->CardState |=
-                               (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
-                       status->CardState |=
-                               (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
-                       status->CardState |=
-                               (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
-               } else {
-                       /* No PRR?  Then assume we're always ready */
-                       status->CardState |= CS_EVENT_READY_CHANGE;
-               }
-               if (c->CardValues & PRESENT_EXT_STATUS) {
-                       pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
-                       status->CardState |=
-                               (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
-               }
-               return CS_SUCCESS;
-       }
-       status->CardState |=
-               (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
-       status->CardState |=
-               (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
-       status->CardState |=
-               (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
-       status->CardState |=
-               (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
-       return CS_SUCCESS;
-} /* pccard_get_status */
-
-int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status)
-{
-       return pccard_get_status(p_dev->socket, p_dev, status);
-}
-EXPORT_SYMBOL(pcmcia_get_status);
-
-
-
 /** pcmcia_get_mem_page
  *
  * Change the card address of an already open memory window.
@@ -812,6 +742,15 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
                type = IRQF_SHARED;
 
 #ifdef CONFIG_PCMCIA_PROBE
+
+#ifdef IRQ_NOAUTOEN
+       /* if the underlying IRQ infrastructure allows for it, only allocate
+        * the IRQ, but do not enable it
+        */
+       if (!(req->Attributes & IRQ_HANDLE_PRESENT))
+               type |= IRQ_NOAUTOEN;
+#endif /* IRQ_NOAUTOEN */
+
        if (s->irq.AssignedIRQ != 0) {
                /* If the interrupt is already assigned, it must be the same */
                irq = s->irq.AssignedIRQ;
@@ -966,7 +905,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) {
        pcmcia_release_configuration(p_dev);
        pcmcia_release_io(p_dev, &p_dev->io);
        pcmcia_release_irq(p_dev, &p_dev->irq);
-       if (&p_dev->win)
+       if (p_dev->win)
                pcmcia_release_window(p_dev->win);
 }
 EXPORT_SYMBOL(pcmcia_disable_device);
index 9414163c78e7ec2582a7c58848a02387e893c0a2..ccfdf1969a7f643bf41686c40399afdfffcaca99 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 
 #include "cs_internal.h"
index ce2226273aaa72fa4f55b8d5d718c9014a231602..c0e2afc79e3e4555877562498d30035aa65815ae 100644 (file)
 #include "cs_internal.h"
 
 
-#ifdef CONFIG_PCMCIA_IOCTL
-
-#ifdef CONFIG_PCMCIA_PROBE
-
-static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
-{
-       int irq;
-       u32 mask;
-
-       irq = adj->resource.irq.IRQ;
-       if ((irq < 0) || (irq > 15))
-               return CS_BAD_IRQ;
-
-       if (adj->Action != REMOVE_MANAGED_RESOURCE)
-               return 0;
-
-       mask = 1 << irq;
-
-       if (!(s->irq_mask & mask))
-               return 0;
-
-       s->irq_mask &= ~mask;
-
-       return 0;
-}
-
-#else
-
-static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
-       return CS_SUCCESS;
-}
-
-#endif
-
-
-int pcmcia_adjust_resource_info(adjust_t *adj)
-{
-       struct pcmcia_socket *s;
-       int ret = CS_UNSUPPORTED_FUNCTION;
-       unsigned long flags;
-
-       down_read(&pcmcia_socket_list_rwsem);
-       list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
-
-               if (adj->Resource == RES_IRQ)
-                       ret = adjust_irq(s, adj);
-
-               else if (s->resource_ops->adjust_resource) {
-
-                       /* you can't use the old interface if the new
-                        * one was used before */
-                       spin_lock_irqsave(&s->lock, flags);
-                       if ((s->resource_setup_new) &&
-                           !(s->resource_setup_old)) {
-                               spin_unlock_irqrestore(&s->lock, flags);
-                               continue;
-                       } else if (!(s->resource_setup_old))
-                               s->resource_setup_old = 1;
-                       spin_unlock_irqrestore(&s->lock, flags);
-
-                       ret = s->resource_ops->adjust_resource(s, adj);
-                       if (!ret) {
-                               /* as there's no way we know this is the
-                                * last call to adjust_resource_info, we
-                                * always need to assume this is the latest
-                                * one... */
-                               spin_lock_irqsave(&s->lock, flags);
-                               s->resource_setup_done = 1;
-                               spin_unlock_irqrestore(&s->lock, flags);
-                       }
-               }
-       }
-       up_read(&pcmcia_socket_list_rwsem);
-
-       return (ret);
-}
-EXPORT_SYMBOL(pcmcia_adjust_resource_info);
-
-#endif
-
 int pcmcia_validate_mem(struct pcmcia_socket *s)
 {
        if (s->resource_ops->validate_mem)
@@ -164,7 +84,8 @@ struct pccard_resource_ops pccard_static_ops = {
        .adjust_io_region = NULL,
        .find_io = NULL,
        .find_mem = NULL,
-       .adjust_resource = NULL,
+       .add_io = NULL,
+       .add_mem = NULL,
        .init = static_init,
        .exit = NULL,
 };
@@ -264,7 +185,8 @@ struct pccard_resource_ops pccard_iodyn_ops = {
        .adjust_io_region = iodyn_adjust_io_region,
        .find_io = iodyn_find_io_region,
        .find_mem = NULL,
-       .adjust_resource = NULL,
+       .add_io = NULL,
+       .add_mem = NULL,
        .init = static_init,
        .exit = NULL,
 };
index 0fcf763b9175a077768d6e85b9a933e24ef52967..d0c1d63d1891bbe7a87587d79e120cfce4aef813 100644 (file)
@@ -31,7 +31,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
@@ -261,21 +260,22 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
 ======================================================================*/
 
 /* Validation function for cards with a valid CIS */
-static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info)
+static int readable(struct pcmcia_socket *s, struct resource *res,
+                   unsigned int *count)
 {
        int ret = -1;
 
        s->cis_mem.res = res;
        s->cis_virt = ioremap(res->start, s->map_size);
        if (s->cis_virt) {
-               ret = pccard_validate_cis(s, BIND_FN_ALL, info);
+               ret = pccard_validate_cis(s, BIND_FN_ALL, count);
                /* invalidate mapping and CIS cache */
                iounmap(s->cis_virt);
                s->cis_virt = NULL;
                destroy_cis_cache(s);
        }
        s->cis_mem.res = NULL;
-       if ((ret != 0) || (info->Chains == 0))
+       if ((ret != 0) || (count == 0))
                return 0;
        return 1;
 }
@@ -316,7 +316,7 @@ static int
 cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
 {
        struct resource *res1, *res2;
-       cisinfo_t info1, info2;
+       unsigned int info1, info2;
        int ret = 0;
 
        res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe");
@@ -330,7 +330,7 @@ cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
        free_region(res2);
        free_region(res1);
 
-       return (ret == 2) && (info1.Chains == info2.Chains);
+       return (ret == 2) && (info1 == info2);
 }
 
 static int
@@ -766,21 +766,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
 }
 
 
-static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj)
-{
-       unsigned long end;
-
-       switch (adj->Resource) {
-       case RES_MEMORY_RANGE:
-               end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
-               return adjust_memory(s, adj->Action, adj->resource.memory.Base, end);
-       case RES_IO_RANGE:
-               end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
-               return adjust_io(s, adj->Action, adj->resource.io.BasePort, end);
-       }
-       return CS_UNSUPPORTED_FUNCTION;
-}
-
 #ifdef CONFIG_PCI
 static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
 {
@@ -889,7 +874,8 @@ struct pccard_resource_ops pccard_nonstatic_ops = {
        .adjust_io_region = nonstatic_adjust_io_region,
        .find_io = nonstatic_find_io_region,
        .find_mem = nonstatic_find_mem_region,
-       .adjust_resource = nonstatic_adjust_resource_info,
+       .add_io = adjust_io,
+       .add_mem = adjust_memory,
        .init = nonstatic_init,
        .exit = nonstatic_release_resource_db,
 };
@@ -1008,41 +994,34 @@ static ssize_t store_mem_db(struct device *dev,
 }
 static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
 
-static struct device_attribute *pccard_rsrc_attributes[] = {
-       &dev_attr_available_resources_io,
-       &dev_attr_available_resources_mem,
+static struct attribute *pccard_rsrc_attributes[] = {
+       &dev_attr_available_resources_io.attr,
+       &dev_attr_available_resources_mem.attr,
        NULL,
 };
 
+static const struct attribute_group rsrc_attributes = {
+       .attrs = pccard_rsrc_attributes,
+};
+
 static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
                                           struct class_interface *class_intf)
 {
        struct pcmcia_socket *s = dev_get_drvdata(dev);
-       struct device_attribute **attr;
-       int ret = 0;
+
        if (s->resource_ops != &pccard_nonstatic_ops)
                return 0;
-
-       for (attr = pccard_rsrc_attributes; *attr; attr++) {
-               ret = device_create_file(dev, *attr);
-               if (ret)
-                       break;
-       }
-
-       return ret;
+       return sysfs_create_group(&dev->kobj, &rsrc_attributes);
 }
 
 static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
                                               struct class_interface *class_intf)
 {
        struct pcmcia_socket *s = dev_get_drvdata(dev);
-       struct device_attribute **attr;
 
        if (s->resource_ops != &pccard_nonstatic_ops)
                return;
-
-       for (attr = pccard_rsrc_attributes; *attr; attr++)
-               device_remove_file(dev, *attr);
+       sysfs_remove_group(&dev->kobj, &rsrc_attributes);
 }
 
 static struct class_interface pccard_rsrc_interface __refdata = {
index 1edc1da9d3537b208c3af78e8de487e752477f91..91ef6a0da3ab14d84893ee47129de75876d7cf4d 100644 (file)
@@ -14,7 +14,6 @@
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
index 562384d6f3213b71e0f9f83999b4579b3d3b16e5..006a29e91d83d58118ee8ff5a40234a45efcc85e 100644 (file)
 #include <asm/system.h>
 #include <asm/irq.h>
 
-#define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -293,7 +291,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
                count = 0;
        else {
                struct pcmcia_socket *s;
-               cisinfo_t cisinfo;
+               unsigned int chains;
 
                if (off + count > size)
                        count = size - off;
@@ -302,9 +300,9 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
 
                if (!(s->state & SOCKET_PRESENT))
                        return -ENODEV;
-               if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo))
+               if (pccard_validate_cis(s, BIND_FN_ALL, &chains))
                        return -EIO;
-               if (!cisinfo.Chains)
+               if (!chains)
                        return -ENODATA;
 
                count = pccard_extract_cis(s, buf, off, count);
index d29657bf1b40faecefd0598ad73cc60c42d292c1..129db7bd06c3661e291204f893bb4c6dedbcccd6 100644 (file)
 #define ENE_TEST_C9_TLTENABLE          0x02
 #define ENE_TEST_C9_PFENABLE_F0                0x04
 #define ENE_TEST_C9_PFENABLE_F1                0x08
-#define ENE_TEST_C9_PFENABLE           (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F0)
+#define ENE_TEST_C9_PFENABLE           (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F1)
 #define ENE_TEST_C9_WPDISALBLE_F0      0x40
 #define ENE_TEST_C9_WPDISALBLE_F1      0x80
 #define ENE_TEST_C9_WPDISALBLE         (ENE_TEST_C9_WPDISALBLE_F0 | ENE_TEST_C9_WPDISALBLE_F1)
@@ -692,7 +692,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket)
                goto out;
 
        /* check state */
-       yenta_get_status(&socket->socket, &state);
+       yenta_get_status(&slot2->socket, &state);
        if (state & SS_DETECT) {
                ret = 0;
                goto out;
index 2ef8cdfda4a74fd506cae8b5cd2d9d14971b4cc4..90b9a6503e1561d2576dbb4ab74bd830bc40e4b4 100644 (file)
@@ -265,6 +265,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, rtc);
+       device_init_wakeup(&pdev->dev, 1);
 
        dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n",
                        (unsigned long)rtc->regs, rtc->irq);
@@ -284,6 +285,8 @@ static int __exit at32_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
 
+       device_init_wakeup(&pdev->dev, 0);
+
        free_irq(rtc->irq, rtc);
        iounmap(rtc->regs);
        rtc_device_unregister(rtc->rtc);
index 1a40256833625e4ea9da26f92e679e9f878b9971..1b6c52ef73391da1aff66cc1aa6bcda8c193ddd8 100644 (file)
@@ -995,14 +995,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        now = get_clock();
 
        DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x",
-                 cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
-                 (unsigned int) intparm);
+                 cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) |
+                 irb->scsw.cmd.dstat), (unsigned int) intparm);
 
        /* check for unsolicited interrupts */
        cqr = (struct dasd_ccw_req *) intparm;
-       if (!cqr || ((irb->scsw.cc == 1) &&
-                    (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
-                    (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
+       if (!cqr || ((irb->scsw.cmd.cc == 1) &&
+                    (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
+                    (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) {
                if (cqr && cqr->status == DASD_CQR_IN_IO)
                        cqr->status = DASD_CQR_QUEUED;
                device = dasd_device_from_cdev_locked(cdev);
@@ -1025,7 +1025,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 
        /* Check for clear pending */
        if (cqr->status == DASD_CQR_CLEAR_PENDING &&
-           irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
+           irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) {
                cqr->status = DASD_CQR_CLEARED;
                dasd_device_clear_timer(device);
                wake_up(&dasd_flush_wq);
@@ -1041,11 +1041,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                return;
        }
        DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
-                     ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
+                     ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr);
        next = NULL;
        expires = 0;
-       if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
-           irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
+       if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+           irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) {
                /* request was completed successfully */
                cqr->status = DASD_CQR_SUCCESS;
                cqr->stopclk = now;
index e6700df52df48750ea00d544d61972bb0212e518..5c6e6f331cb0691e097f55321eb5fe37007adbb3 100644 (file)
@@ -1572,7 +1572,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
        /* determine the address of the CCW to be restarted */
        /* Imprecise ending is not set -> addr from IRB-SCSW */
-       cpa = default_erp->refers->irb.scsw.cpa;
+       cpa = default_erp->refers->irb.scsw.cmd.cpa;
 
        if (cpa == 0) {
 
@@ -1725,7 +1725,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 
        /* determine the address of the CCW to be restarted */
        /* Imprecise ending is not set -> addr from IRB-SCSW */
-       cpa = previous_erp->irb.scsw.cpa;
+       cpa = previous_erp->irb.scsw.cmd.cpa;
 
        if (cpa == 0) {
 
@@ -2171,7 +2171,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp)
 {
        struct dasd_device *device = erp->startdev;
 
-       if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK
+       if (erp->refers->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK
                                           | SCHN_STAT_CHN_CTRL_CHK)) {
                DEV_MESSAGE(KERN_DEBUG, device, "%s",
                            "channel or interface control check");
@@ -2352,9 +2352,9 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
 
        if ((cqr1->irb.esw.esw0.erw.cons == 0) &&
            (cqr2->irb.esw.esw0.erw.cons == 0)) {
-               if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
+               if ((cqr1->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK |
                                             SCHN_STAT_CHN_CTRL_CHK)) ==
-                   (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
+                   (cqr2->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK |
                                             SCHN_STAT_CHN_CTRL_CHK)))
                        return 1; /* match with ifcc*/
        }
@@ -2622,8 +2622,9 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
        }
 
        /* double-check if current erp/cqr was successfull */
-       if ((cqr->irb.scsw.cstat == 0x00) &&
-           (cqr->irb.scsw.dstat == (DEV_STAT_CHN_END|DEV_STAT_DEV_END))) {
+       if ((cqr->irb.scsw.cmd.cstat == 0x00) &&
+           (cqr->irb.scsw.cmd.dstat ==
+            (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
 
                DEV_MESSAGE(KERN_DEBUG, device,
                            "ERP called for successful request %p"
index a0edae091b5e54f1c022115ab60b8912ff3324f3..e0b77210d37a5b95f15b707c39baf42397396ba2 100644 (file)
@@ -1404,13 +1404,14 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
 
        /* first of all check for state change pending interrupt */
        mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-       if ((irb->scsw.dstat & mask) == mask) {
+       if ((irb->scsw.cmd.dstat & mask) == mask) {
                dasd_generic_handle_state_change(device);
                return;
        }
 
        /* summary unit check */
-       if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) {
+       if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
+           (irb->ecw[7] == 0x0D)) {
                dasd_alias_handle_summary_unit_check(device, irb);
                return;
        }
@@ -2068,11 +2069,11 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
                      device->cdev->dev.bus_id);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
-                      irb->scsw.cstat, irb->scsw.dstat);
+                      irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " device %s: Failing CCW: %p\n",
                       device->cdev->dev.bus_id,
-                      (void *) (addr_t) irb->scsw.cpa);
+                      (void *) (addr_t) irb->scsw.cmd.cpa);
        if (irb->esw.esw0.erw.cons) {
                for (sl = 0; sl < 4; sl++) {
                        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -2122,7 +2123,8 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
                /* scsw->cda is either valid or zero  */
                len = 0;
                from = ++to;
-               fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+               fail = (struct ccw1 *)(addr_t)
+                               irb->scsw.cmd.cpa; /* failing CCW */
                if (from <  fail - 2) {
                        from = fail - 2;     /* there is a gap - print header */
                        len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
index 116611583df8215ea1ec7ecc6f9d25987812b00d..aee4656127f76e9ddeb8dc2439b2bbf38ea30efb 100644 (file)
@@ -222,7 +222,7 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
 
        /* first of all check for state change pending interrupt */
        mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-       if ((irb->scsw.dstat & mask) == mask) {
+       if ((irb->scsw.cmd.dstat & mask) == mask) {
                dasd_generic_handle_state_change(device);
                return;
        }
@@ -449,11 +449,11 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                      device->cdev->dev.bus_id);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
-                      irb->scsw.cstat, irb->scsw.dstat);
+                      irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                       " device %s: Failing CCW: %p\n",
                       device->cdev->dev.bus_id,
-                      (void *) (addr_t) irb->scsw.cpa);
+                      (void *) (addr_t) irb->scsw.cmd.cpa);
        if (irb->esw.esw0.erw.cons) {
                for (sl = 0; sl < 4; sl++) {
                        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -498,11 +498,11 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 
        /* print failing CCW area */
        len = 0;
-       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {
-               act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;
+       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2) {
+               act = ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2;
                len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
        }
-       end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);
+       end = min((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa + 2, last);
        while (act <= end) {
                len += sprintf(page + len, KERN_ERR PRINTK_HEADER
                               " CCW %p: %08X %08X DAT:",
index bb52d2fbac183b7a98e4e7872ace113a92a8cecc..01fcdd91b846533a920cc3076c67bf85ca3816c2 100644 (file)
@@ -167,10 +167,8 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
        struct dcssblk_dev_info *dev_info;
        int rc;
 
-       if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) {
-               PRINT_WARN("Invalid value, must be 0 or 1\n");
+       if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
                return -EINVAL;
-       }
        down_write(&dcssblk_devices_sem);
        dev_info = container_of(dev, struct dcssblk_dev_info, dev);
        if (atomic_read(&dev_info->use_count)) {
@@ -215,7 +213,6 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
                        set_disk_ro(dev_info->gd, 0);
                }
        } else {
-               PRINT_WARN("Invalid value, must be 0 or 1\n");
                rc = -EINVAL;
                goto out;
        }
@@ -258,10 +255,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
 {
        struct dcssblk_dev_info *dev_info;
 
-       if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) {
-               PRINT_WARN("Invalid value, must be 0 or 1\n");
+       if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
                return -EINVAL;
-       }
        dev_info = container_of(dev, struct dcssblk_dev_info, dev);
 
        down_write(&dcssblk_devices_sem);
@@ -289,7 +284,6 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
                }
        } else {
                up_write(&dcssblk_devices_sem);
-               PRINT_WARN("Invalid value, must be 0 or 1\n");
                return -EINVAL;
        }
        up_write(&dcssblk_devices_sem);
@@ -441,7 +435,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        goto out;
 
 unregister_dev:
-       PRINT_ERR("device_create_file() failed!\n");
        list_del(&dev_info->lh);
        blk_cleanup_queue(dev_info->dcssblk_queue);
        dev_info->gd->queue = NULL;
@@ -702,10 +695,8 @@ dcssblk_check_params(void)
 static void __exit
 dcssblk_exit(void)
 {
-       PRINT_DEBUG("DCSSBLOCK EXIT...\n");
        s390_root_dev_unregister(dcssblk_root_dev);
        unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
-       PRINT_DEBUG("...finished!\n");
 }
 
 static int __init
@@ -713,27 +704,21 @@ dcssblk_init(void)
 {
        int rc;
 
-       PRINT_DEBUG("DCSSBLOCK INIT...\n");
        dcssblk_root_dev = s390_root_dev_register("dcssblk");
-       if (IS_ERR(dcssblk_root_dev)) {
-               PRINT_ERR("device_register() failed!\n");
+       if (IS_ERR(dcssblk_root_dev))
                return PTR_ERR(dcssblk_root_dev);
-       }
        rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
        if (rc) {
-               PRINT_ERR("device_create_file(add) failed!\n");
                s390_root_dev_unregister(dcssblk_root_dev);
                return rc;
        }
        rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
        if (rc) {
-               PRINT_ERR("device_create_file(remove) failed!\n");
                s390_root_dev_unregister(dcssblk_root_dev);
                return rc;
        }
        rc = register_blkdev(0, DCSSBLK_NAME);
        if (rc < 0) {
-               PRINT_ERR("Can't get dynamic major!\n");
                s390_root_dev_unregister(dcssblk_root_dev);
                return rc;
        }
@@ -742,7 +727,6 @@ dcssblk_init(void)
 
        dcssblk_check_params();
 
-       PRINT_DEBUG("...finished!\n");
        return 0;
 }
 
index f231bc21b1cafd3465dcf97cc3c4f6618b5b804c..dd9b986389a2bf4a2d38a71a64c01dfe25718ef3 100644 (file)
@@ -100,15 +100,10 @@ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
                : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
        if (cc == 3)
                return -ENXIO;
-       if (cc == 2) {
-               PRINT_ERR("expanded storage lost!\n");
+       if (cc == 2)
                return -ENXIO;
-       }
-       if (cc == 1) {
-               PRINT_ERR("page in failed for page index %u.\n",
-                         xpage_index);
+       if (cc == 1)
                return -EIO;
-       }
        return 0;
 }
 
@@ -135,15 +130,10 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
                : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
        if (cc == 3)
                return -ENXIO;
-       if (cc == 2) {
-               PRINT_ERR("expanded storage lost!\n");
+       if (cc == 2)
                return -ENXIO;
-       }
-       if (cc == 1) {
-               PRINT_ERR("page out failed for page index %u.\n",
-                         xpage_index);
+       if (cc == 1)
                return -EIO;
-       }
        return 0;
 }
 
index 3e5653c92f4b5e5b6d1c5b1edd14b5f6eaa23af6..d3ec9b55ab351c665016c0c1fd139a6cf841fa9f 100644 (file)
@@ -93,9 +93,6 @@ struct raw3215_info {
        struct raw3215_req *queued_write;/* pointer to queued write requests */
        wait_queue_head_t empty_wait; /* wait queue for flushing */
        struct timer_list timer;      /* timer for delayed output */
-       char *message;                /* pending message from raw3215_irq */
-       int msg_dstat;                /* dstat for pending message */
-       int msg_cstat;                /* cstat for pending message */
        int line_pos;                 /* position on the line (for tabs) */
        char ubuffer[80];             /* copy_from_user buffer */
 };
@@ -359,11 +356,6 @@ raw3215_tasklet(void *data)
        raw3215_mk_write_req(raw);
        raw3215_try_io(raw);
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
-       /* Check for pending message from raw3215_irq */
-       if (raw->message != NULL) {
-               printk(raw->message, raw->msg_dstat, raw->msg_cstat);
-               raw->message = NULL;
-       }
        tty = raw->tty;
        if (tty != NULL &&
            RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
@@ -381,20 +373,14 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        struct raw3215_req *req;
        struct tty_struct *tty;
        int cstat, dstat;
-       int count, slen;
+       int count;
 
        raw = cdev->dev.driver_data;
        req = (struct raw3215_req *) intparm;
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
-       if (cstat != 0) {
-               raw->message = KERN_WARNING
-                       "Got nonzero channel status in raw3215_irq "
-                       "(dev sts 0x%2x, sch sts 0x%2x)";
-               raw->msg_dstat = dstat;
-               raw->msg_cstat = cstat;
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
+       if (cstat != 0)
                tasklet_schedule(&raw->tasklet);
-       }
        if (dstat & 0x01) { /* we got a unit exception */
                dstat &= ~0x01;  /* we can ignore it */
        }
@@ -404,8 +390,6 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                        break;
                /* Attention interrupt, someone hit the enter key */
                raw3215_mk_read_req(raw);
-               if (MACHINE_IS_P390)
-                       memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
                tasklet_schedule(&raw->tasklet);
                break;
        case 0x08:
@@ -415,7 +399,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                        return;              /* That shouldn't happen ... */
                if (req->type == RAW3215_READ) {
                        /* store residual count, then wait for device end */
-                       req->residual = irb->scsw.count;
+                       req->residual = irb->scsw.cmd.count;
                }
                if (dstat == 0x08)
                        break;
@@ -428,11 +412,6 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
 
                        tty = raw->tty;
                        count = 160 - req->residual;
-                       if (MACHINE_IS_P390) {
-                               slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
-                               if (count > slen)
-                                       count = slen;
-                       } else
                        EBCASC(raw->inbuf, count);
                        cchar = ctrlchar_handle(raw->inbuf, count, tty);
                        switch (cchar & CTRLCHAR_MASK) {
@@ -481,11 +460,6 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                        raw->flags &= ~RAW3215_WORKING;
                        raw3215_free_req(req);
                }
-               raw->message = KERN_WARNING
-                       "Spurious interrupt in in raw3215_irq "
-                       "(dev sts 0x%2x, sch sts 0x%2x)";
-               raw->msg_dstat = dstat;
-               raw->msg_cstat = cstat;
                tasklet_schedule(&raw->tasklet);
        }
        return;
@@ -883,7 +857,6 @@ con3215_init(void)
                free_bootmem((unsigned long) raw->buffer, RAW3215_BUFFER_SIZE);
                free_bootmem((unsigned long) raw, sizeof(struct raw3215_info));
                raw3215[0] = NULL;
-               printk("Couldn't find a 3215 console device\n");
                return -ENODEV;
        }
        register_console(&con3215);
@@ -1157,7 +1130,6 @@ tty3215_init(void)
        tty_set_operations(driver, &tty3215_ops);
        ret = tty_register_driver(driver);
        if (ret) {
-               printk("Couldn't register tty3215 driver\n");
                put_tty_driver(driver);
                return ret;
        }
index 0b040557db02d5ee67ad91c4179f4179d14d6a54..3c07974886ed2aa1f8fa23dea19fd7e3b77860c0 100644 (file)
@@ -411,15 +411,15 @@ static int
 con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb)
 {
        /* Handle ATTN. Schedule tasklet to read aid. */
-       if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+       if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION)
                con3270_issue_read(cp);
 
        if (rq) {
-               if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
+               if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
                        rq->rc = -EIO;
                else
                        /* Normal end. Copy residual count. */
-                       rq->rescnt = irb->scsw.count;
+                       rq->rescnt = irb->scsw.cmd.count;
        }
        return RAW3270_IO_DONE;
 }
index ef36f2132aa43fb994ee878a46022f5776c64ed0..e136d10a0de6da541f788937d32fd0a513091e0f 100644 (file)
@@ -216,17 +216,17 @@ static int
 fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
 {
        /* Handle ATTN. Set indication and wake waiters for attention. */
-       if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
                fp->attention = 1;
                wake_up(&fp->wait);
        }
 
        if (rq) {
-               if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
+               if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
                        rq->rc = -EIO;
                else
                        /* Normal end. Copy residual count. */
-                       rq->rescnt = irb->scsw.count;
+                       rq->rescnt = irb->scsw.cmd.count;
        }
        return RAW3270_IO_DONE;
 }
@@ -512,11 +512,8 @@ fs3270_init(void)
        int rc;
 
        rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
-       if (rc) {
-               printk(KERN_ERR "fs3270 can't get major number %d: errno %d\n",
-                      IBM_FS3270_MAJOR, rc);
+       if (rc)
                return rc;
-       }
        return 0;
 }
 
index 1e1f50655bbfb8f01a4896dd830a09ff23f98f99..f0e4c96afbf803f12c17f296d0fd645a57cb93b4 100644 (file)
@@ -3,9 +3,8 @@
  *
  * Character device driver for reading z/VM *MONITOR service records.
  *
- * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
- *
- * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ *   Copyright IBM Corp. 2004, 2008
+ *   Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <net/iucv/iucv.h>
 #include <asm/uaccess.h>
 #include <asm/ebcdic.h>
 #include <asm/extmem.h>
-#include <linux/poll.h>
-#include <net/iucv/iucv.h>
-
 
 //#define MON_DEBUG                    /* Debug messages on/off */
 
@@ -152,10 +150,7 @@ static int mon_check_mca(struct mon_msg *monmsg)
            (mon_mca_end(monmsg) > mon_dcss_end) ||
            (mon_mca_start(monmsg) < mon_dcss_start) ||
            ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0)))
-       {
-               P_DEBUG("READ, IGNORED INVALID MCA\n\n");
                return -EINVAL;
-       }
        return 0;
 }
 
@@ -164,10 +159,6 @@ static int mon_send_reply(struct mon_msg *monmsg,
 {
        int rc;
 
-       P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = "
-               "0x%08X\n\n",
-               monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
-
        rc = iucv_message_reply(monpriv->path, &monmsg->msg,
                                IUCV_IPRMDATA, NULL, 0);
        atomic_dec(&monpriv->msglim_count);
@@ -202,15 +193,12 @@ static struct mon_private *mon_alloc_mem(void)
        struct mon_private *monpriv;
 
        monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
-       if (!monpriv) {
-               P_ERROR("no memory for monpriv\n");
+       if (!monpriv)
                return NULL;
-       }
        for (i = 0; i < MON_MSGLIM; i++) {
                monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg),
                                                    GFP_KERNEL);
                if (!monpriv->msg_array[i]) {
-                       P_ERROR("open, no memory for msg_array\n");
                        mon_free_mem(monpriv);
                        return NULL;
                }
@@ -218,41 +206,10 @@ static struct mon_private *mon_alloc_mem(void)
        return monpriv;
 }
 
-static inline void mon_read_debug(struct mon_msg *monmsg,
-                                 struct mon_private *monpriv)
-{
-#ifdef MON_DEBUG
-       u8 msg_type[2], mca_type;
-       unsigned long records_len;
-
-       records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1;
-
-       memcpy(msg_type, &monmsg->msg.class, 2);
-       EBCASC(msg_type, 2);
-       mca_type = mon_mca_type(monmsg, 0);
-       EBCASC(&mca_type, 1);
-
-       P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n",
-               monpriv->read_index, monpriv->write_index);
-       P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n",
-               monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
-       P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n",
-               msg_type[0], msg_type[1], mca_type ? mca_type : 'X',
-               mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2));
-       P_DEBUG("read, MCA: start = 0x%lX, end = 0x%lX\n",
-               mon_mca_start(monmsg), mon_mca_end(monmsg));
-       P_DEBUG("read, REC: start = 0x%X, end = 0x%X, len = %lu\n\n",
-               mon_rec_start(monmsg), mon_rec_end(monmsg), records_len);
-       if (mon_mca_size(monmsg) > 12)
-               P_DEBUG("READ, MORE THAN ONE MCA\n\n");
-#endif
-}
-
 static inline void mon_next_mca(struct mon_msg *monmsg)
 {
        if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
                return;
-       P_DEBUG("READ, NEXT MCA\n\n");
        monmsg->mca_offset += 12;
        monmsg->pos = 0;
 }
@@ -269,7 +226,6 @@ static struct mon_msg *mon_next_message(struct mon_private *monpriv)
                monmsg->msglim_reached = 0;
                monmsg->pos = 0;
                monmsg->mca_offset = 0;
-               P_WARNING("read, message limit reached\n");
                monpriv->read_index = (monpriv->read_index + 1) %
                                      MON_MSGLIM;
                atomic_dec(&monpriv->read_ready);
@@ -286,10 +242,6 @@ static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
 {
        struct mon_private *monpriv = path->private;
 
-       P_DEBUG("IUCV connection completed\n");
-       P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = "
-               "0x%02X, Sample = 0x%02X\n",
-               ipuser[0], ipuser[1], ipuser[2]);
        atomic_set(&monpriv->iucv_connected, 1);
        wake_up(&mon_conn_wait_queue);
 }
@@ -310,7 +262,6 @@ static void mon_iucv_message_pending(struct iucv_path *path,
 {
        struct mon_private *monpriv = path->private;
 
-       P_DEBUG("IUCV message pending\n");
        memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
               msg, sizeof(*msg));
        if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
@@ -375,7 +326,6 @@ static int mon_open(struct inode *inode, struct file *filp)
                rc = -EIO;
                goto out_path;
        }
-       P_INFO("open, established connection to *MONITOR service\n\n");
        filp->private_data = monpriv;
        return nonseekable_open(inode, filp);
 
@@ -400,8 +350,6 @@ static int mon_close(struct inode *inode, struct file *filp)
        rc = iucv_path_sever(monpriv->path, user_data_sever);
        if (rc)
                P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
-       else
-               P_INFO("close, terminated connection to *MONITOR service\n");
 
        atomic_set(&monpriv->iucv_severed, 0);
        atomic_set(&monpriv->iucv_connected, 0);
@@ -442,10 +390,8 @@ static ssize_t mon_read(struct file *filp, char __user *data,
                monmsg = monpriv->msg_array[monpriv->read_index];
        }
 
-       if (!monmsg->pos) {
+       if (!monmsg->pos)
                monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset;
-               mon_read_debug(monmsg, monpriv);
-       }
        if (mon_check_mca(monmsg))
                goto reply;
 
@@ -531,7 +477,6 @@ static int __init mon_init(void)
                P_ERROR("failed to register with iucv driver\n");
                return rc;
        }
-       P_INFO("open, registered with IUCV\n");
 
        rc = segment_type(mon_dcss_name);
        if (rc < 0) {
@@ -555,13 +500,8 @@ static int __init mon_init(void)
        dcss_mkname(mon_dcss_name, &user_data_connect[8]);
 
        rc = misc_register(&mon_dev);
-       if (rc < 0 ) {
-               P_ERROR("misc_register failed, rc = %i\n", rc);
+       if (rc < 0 )
                goto out;
-       }
-       P_INFO("Loaded segment %s from %p to %p, size = %lu Byte\n",
-               mon_dcss_name, (void *) mon_dcss_start, (void *) mon_dcss_end,
-               mon_dcss_end - mon_dcss_start + 1);
        return 0;
 
 out:
index 848ef7e8523fe97ba2e0ade9f61f1cbac86a8f90..81a96e019080bf591ab68e3dee40b593ab2ff9f8 100644 (file)
@@ -153,19 +153,10 @@ struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size)
        struct raw3270_request *rq;
 
        rq = alloc_bootmem_low(sizeof(struct raw3270));
-       if (!rq)
-               return ERR_PTR(-ENOMEM);
-       memset(rq, 0, sizeof(struct raw3270_request));
 
        /* alloc output buffer. */
-       if (size > 0) {
+       if (size > 0)
                rq->buffer = alloc_bootmem_low(size);
-               if (!rq->buffer) {
-                       free_bootmem((unsigned long) rq,
-                                    sizeof(struct raw3270));
-                       return ERR_PTR(-ENOMEM);
-               }
-       }
        rq->size = size;
        INIT_LIST_HEAD(&rq->list);
 
@@ -372,17 +363,17 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
 
        if (IS_ERR(irb))
                rc = RAW3270_IO_RETRY;
-       else if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) {
+       else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) {
                rq->rc = -EIO;
                rc = RAW3270_IO_DONE;
-       } else if (irb->scsw.dstat ==  (DEV_STAT_CHN_END | DEV_STAT_DEV_END |
-                                       DEV_STAT_UNIT_EXCEP)) {
+       } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END |
+                                          DEV_STAT_UNIT_EXCEP)) {
                /* Handle CE-DE-UE and subsequent UDE */
                set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
                rc = RAW3270_IO_BUSY;
        } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
                /* Wait for UDE if busy flag is set. */
-               if (irb->scsw.dstat & DEV_STAT_DEV_END) {
+               if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
                        clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
                        /* Got it, now retry. */
                        rc = RAW3270_IO_RETRY;
@@ -497,7 +488,7 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
         * Unit-Check Processing:
         * Expect Command Reject or Intervention Required.
         */
-       if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
                /* Request finished abnormally. */
                if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
                        set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
@@ -505,16 +496,16 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
                }
        }
        if (rq) {
-               if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+               if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
                        if (irb->ecw[0] & SNS0_CMD_REJECT)
                                rq->rc = -EOPNOTSUPP;
                        else
                                rq->rc = -EIO;
                } else
                        /* Request finished normally. Copy residual count. */
-                       rq->rescnt = irb->scsw.count;
+                       rq->rescnt = irb->scsw.cmd.count;
        }
-       if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
                set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags);
                wake_up(&raw3270_wait_queue);
        }
@@ -619,7 +610,6 @@ __raw3270_size_device_vm(struct raw3270 *rp)
                rp->cols = 132;
                break;
        default:
-               printk(KERN_WARNING "vrdccrmd is 0x%.8x\n", model);
                rc = -EOPNOTSUPP;
                break;
        }
index 2c7a1ee6b0410fb1f5fc1eeda314ab837a4d6e29..3c8b25e6c3457b528bb8a90c8e2074ff66faf1b8 100644 (file)
@@ -506,6 +506,8 @@ sclp_state_change_cb(struct evbuf_header *evbuf)
        if (scbuf->validity_sclp_send_mask)
                sclp_send_mask = scbuf->sclp_send_mask;
        spin_unlock_irqrestore(&sclp_lock, flags);
+       if (scbuf->validity_sclp_active_facility_mask)
+               sclp_facilities = scbuf->sclp_active_facility_mask;
        sclp_dispatch_state_change();
 }
 
@@ -782,11 +784,9 @@ sclp_check_handler(__u16 code)
        /* Is this the interrupt we are waiting for? */
        if (finished_sccb == 0)
                return;
-       if (finished_sccb != (u32) (addr_t) sclp_init_sccb) {
-               printk(KERN_WARNING SCLP_HEADER "unsolicited interrupt "
-                      "for buffer at 0x%x\n", finished_sccb);
-               return;
-       }
+       if (finished_sccb != (u32) (addr_t) sclp_init_sccb)
+               panic("sclp: unsolicited interrupt for buffer at 0x%x\n",
+                     finished_sccb);
        spin_lock(&sclp_lock);
        if (sclp_running_state == sclp_running_state_running) {
                sclp_init_req.status = SCLP_REQ_DONE;
@@ -883,8 +883,6 @@ sclp_init(void)
        unsigned long flags;
        int rc;
 
-       if (!MACHINE_HAS_SCLP)
-               return -ENODEV;
        spin_lock_irqsave(&sclp_lock, flags);
        /* Check for previous or running initialization */
        if (sclp_init_state != sclp_init_state_uninitialized) {
index b5c23396f8fe4a8a32bf11bee25002c12d54399d..0c2b77493db44ae564033ea20e247330c0951ae2 100644 (file)
@@ -11,6 +11,9 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/memory.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 #include "sclp.h"
@@ -43,6 +46,8 @@ static int __initdata early_read_info_sccb_valid;
 
 u64 sclp_facilities;
 static u8 sclp_fac84;
+static unsigned long long rzm;
+static unsigned long long rnmax;
 
 static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
 {
@@ -62,7 +67,7 @@ out:
        return rc;
 }
 
-void __init sclp_read_info_early(void)
+static void __init sclp_read_info_early(void)
 {
        int rc;
        int i;
@@ -92,34 +97,33 @@ void __init sclp_read_info_early(void)
 
 void __init sclp_facilities_detect(void)
 {
+       struct read_info_sccb *sccb;
+
+       sclp_read_info_early();
        if (!early_read_info_sccb_valid)
                return;
-       sclp_facilities = early_read_info_sccb.facilities;
-       sclp_fac84 = early_read_info_sccb.fac84;
+
+       sccb = &early_read_info_sccb;
+       sclp_facilities = sccb->facilities;
+       sclp_fac84 = sccb->fac84;
+       rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
+       rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
+       rzm <<= 20;
 }
 
-unsigned long long __init sclp_memory_detect(void)
+unsigned long long sclp_get_rnmax(void)
 {
-       unsigned long long memsize;
-       struct read_info_sccb *sccb;
+       return rnmax;
+}
 
-       if (!early_read_info_sccb_valid)
-               return 0;
-       sccb = &early_read_info_sccb;
-       if (sccb->rnsize)
-               memsize = sccb->rnsize << 20;
-       else
-               memsize = sccb->rnsize2 << 20;
-       if (sccb->rnmax)
-               memsize *= sccb->rnmax;
-       else
-               memsize *= sccb->rnmax2;
-       return memsize;
+unsigned long long sclp_get_rzm(void)
+{
+       return rzm;
 }
 
 /*
- * This function will be called after sclp_memory_detect(), which gets called
- * early from early.c code. Therefore the sccb should have valid contents.
+ * This function will be called after sclp_facilities_detect(), which gets
+ * called from early.c code. Therefore the sccb should have valid contents.
  */
 void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
 {
@@ -278,6 +282,305 @@ int sclp_cpu_deconfigure(u8 cpu)
        return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
 }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static DEFINE_MUTEX(sclp_mem_mutex);
+static LIST_HEAD(sclp_mem_list);
+static u8 sclp_max_storage_id;
+static unsigned long sclp_storage_ids[256 / BITS_PER_LONG];
+
+struct memory_increment {
+       struct list_head list;
+       u16 rn;
+       int standby;
+       int usecount;
+};
+
+struct assign_storage_sccb {
+       struct sccb_header header;
+       u16 rn;
+} __packed;
+
+static unsigned long long rn2addr(u16 rn)
+{
+       return (unsigned long long) (rn - 1) * rzm;
+}
+
+static int do_assign_storage(sclp_cmdw_t cmd, u16 rn)
+{
+       struct assign_storage_sccb *sccb;
+       int rc;
+
+       sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       sccb->header.length = PAGE_SIZE;
+       sccb->rn = rn;
+       rc = do_sync_request(cmd, sccb);
+       if (rc)
+               goto out;
+       switch (sccb->header.response_code) {
+       case 0x0020:
+       case 0x0120:
+               break;
+       default:
+               rc = -EIO;
+               break;
+       }
+out:
+       free_page((unsigned long) sccb);
+       return rc;
+}
+
+static int sclp_assign_storage(u16 rn)
+{
+       return do_assign_storage(0x000d0001, rn);
+}
+
+static int sclp_unassign_storage(u16 rn)
+{
+       return do_assign_storage(0x000c0001, rn);
+}
+
+struct attach_storage_sccb {
+       struct sccb_header header;
+       u16 :16;
+       u16 assigned;
+       u32 :32;
+       u32 entries[0];
+} __packed;
+
+static int sclp_attach_storage(u8 id)
+{
+       struct attach_storage_sccb *sccb;
+       int rc;
+       int i;
+
+       sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       sccb->header.length = PAGE_SIZE;
+       rc = do_sync_request(0x00080001 | id << 8, sccb);
+       if (rc)
+               goto out;
+       switch (sccb->header.response_code) {
+       case 0x0020:
+               set_bit(id, sclp_storage_ids);
+               for (i = 0; i < sccb->assigned; i++)
+                       sclp_unassign_storage(sccb->entries[i] >> 16);
+               break;
+       default:
+               rc = -EIO;
+               break;
+       }
+out:
+       free_page((unsigned long) sccb);
+       return rc;
+}
+
+static int sclp_mem_change_state(unsigned long start, unsigned long size,
+                                int online)
+{
+       struct memory_increment *incr;
+       unsigned long long istart;
+       int rc = 0;
+
+       list_for_each_entry(incr, &sclp_mem_list, list) {
+               istart = rn2addr(incr->rn);
+               if (start + size - 1 < istart)
+                       break;
+               if (start > istart + rzm - 1)
+                       continue;
+               if (online) {
+                       if (incr->usecount++)
+                               continue;
+                       /*
+                        * Don't break the loop if one assign fails. Loop may
+                        * be walked again on CANCEL and we can't save
+                        * information if state changed before or not.
+                        * So continue and increase usecount for all increments.
+                        */
+                       rc |= sclp_assign_storage(incr->rn);
+               } else {
+                       if (--incr->usecount)
+                               continue;
+                       sclp_unassign_storage(incr->rn);
+               }
+       }
+       return rc ? -EIO : 0;
+}
+
+static int sclp_mem_notifier(struct notifier_block *nb,
+                            unsigned long action, void *data)
+{
+       unsigned long start, size;
+       struct memory_notify *arg;
+       unsigned char id;
+       int rc = 0;
+
+       arg = data;
+       start = arg->start_pfn << PAGE_SHIFT;
+       size = arg->nr_pages << PAGE_SHIFT;
+       mutex_lock(&sclp_mem_mutex);
+       for (id = 0; id <= sclp_max_storage_id; id++)
+               if (!test_bit(id, sclp_storage_ids))
+                       sclp_attach_storage(id);
+       switch (action) {
+       case MEM_ONLINE:
+               break;
+       case MEM_GOING_ONLINE:
+               rc = sclp_mem_change_state(start, size, 1);
+               break;
+       case MEM_CANCEL_ONLINE:
+               sclp_mem_change_state(start, size, 0);
+               break;
+       default:
+               rc = -EINVAL;
+               break;
+       }
+       mutex_unlock(&sclp_mem_mutex);
+       return rc ? NOTIFY_BAD : NOTIFY_OK;
+}
+
+static struct notifier_block sclp_mem_nb = {
+       .notifier_call = sclp_mem_notifier,
+};
+
+static void __init add_memory_merged(u16 rn)
+{
+       static u16 first_rn, num;
+       unsigned long long start, size;
+
+       if (rn && first_rn && (first_rn + num == rn)) {
+               num++;
+               return;
+       }
+       if (!first_rn)
+               goto skip_add;
+       start = rn2addr(first_rn);
+       size = (unsigned long long ) num * rzm;
+       if (start >= VMEM_MAX_PHYS)
+               goto skip_add;
+       if (start + size > VMEM_MAX_PHYS)
+               size = VMEM_MAX_PHYS - start;
+       add_memory(0, start, size);
+skip_add:
+       first_rn = rn;
+       num = 1;
+}
+
+static void __init sclp_add_standby_memory(void)
+{
+       struct memory_increment *incr;
+
+       list_for_each_entry(incr, &sclp_mem_list, list)
+               if (incr->standby)
+                       add_memory_merged(incr->rn);
+       add_memory_merged(0);
+}
+
+static void __init insert_increment(u16 rn, int standby, int assigned)
+{
+       struct memory_increment *incr, *new_incr;
+       struct list_head *prev;
+       u16 last_rn;
+
+       new_incr = kzalloc(sizeof(*new_incr), GFP_KERNEL);
+       if (!new_incr)
+               return;
+       new_incr->rn = rn;
+       new_incr->standby = standby;
+       last_rn = 0;
+       prev = &sclp_mem_list;
+       list_for_each_entry(incr, &sclp_mem_list, list) {
+               if (assigned && incr->rn > rn)
+                       break;
+               if (!assigned && incr->rn - last_rn > 1)
+                       break;
+               last_rn = incr->rn;
+               prev = &incr->list;
+       }
+       if (!assigned)
+               new_incr->rn = last_rn + 1;
+       if (new_incr->rn > rnmax) {
+               kfree(new_incr);
+               return;
+       }
+       list_add(&new_incr->list, prev);
+}
+
+struct read_storage_sccb {
+       struct sccb_header header;
+       u16 max_id;
+       u16 assigned;
+       u16 standby;
+       u16 :16;
+       u32 entries[0];
+} __packed;
+
+static int __init sclp_detect_standby_memory(void)
+{
+       struct read_storage_sccb *sccb;
+       int i, id, assigned, rc;
+
+       if (!early_read_info_sccb_valid)
+               return 0;
+       if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL)
+               return 0;
+       rc = -ENOMEM;
+       sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               goto out;
+       assigned = 0;
+       for (id = 0; id <= sclp_max_storage_id; id++) {
+               memset(sccb, 0, PAGE_SIZE);
+               sccb->header.length = PAGE_SIZE;
+               rc = do_sync_request(0x00040001 | id << 8, sccb);
+               if (rc)
+                       goto out;
+               switch (sccb->header.response_code) {
+               case 0x0010:
+                       set_bit(id, sclp_storage_ids);
+                       for (i = 0; i < sccb->assigned; i++) {
+                               if (!sccb->entries[i])
+                                       continue;
+                               assigned++;
+                               insert_increment(sccb->entries[i] >> 16, 0, 1);
+                       }
+                       break;
+               case 0x0310:
+                       break;
+               case 0x0410:
+                       for (i = 0; i < sccb->assigned; i++) {
+                               if (!sccb->entries[i])
+                                       continue;
+                               assigned++;
+                               insert_increment(sccb->entries[i] >> 16, 1, 1);
+                       }
+                       break;
+               default:
+                       rc = -EIO;
+                       break;
+               }
+               if (!rc)
+                       sclp_max_storage_id = sccb->max_id;
+       }
+       if (rc || list_empty(&sclp_mem_list))
+               goto out;
+       for (i = 1; i <= rnmax - assigned; i++)
+               insert_increment(0, 1, 0);
+       rc = register_memory_notifier(&sclp_mem_nb);
+       if (rc)
+               goto out;
+       sclp_add_standby_memory();
+out:
+       free_page((unsigned long) sccb);
+       return rc;
+}
+__initcall(sclp_detect_standby_memory);
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
 /*
  * Channel path configuration related functions.
  */
index ead1043d788ec3338525f83ed9655a8fec5c9072..7e619c534bf46ed7e3078dfcd3a0c44738e427bd 100644 (file)
 #include <linux/timer.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
+#include <linux/termios.h>
 #include <linux/err.h>
 
 #include "sclp.h"
 #include "sclp_rw.h"
 #include "sclp_tty.h"
 
-#define SCLP_CON_PRINT_HEADER "sclp console driver: "
-
 #define sclp_console_major 4           /* TTYAUX_MAJOR */
 #define sclp_console_minor 64
 #define sclp_console_name  "ttyS"
@@ -222,8 +221,6 @@ sclp_console_init(void)
        INIT_LIST_HEAD(&sclp_con_pages);
        for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
                page = alloc_bootmem_low_pages(PAGE_SIZE);
-               if (page == NULL)
-                       return -ENOMEM;
                list_add_tail((struct list_head *) page, &sclp_con_pages);
        }
        INIT_LIST_HEAD(&sclp_con_outqueue);
index ad05a87bc480b14531fdd5570f78c2dc3f93c9c5..fff4ff485d9bcbb8e3bc25c05d465b8214f8774b 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/cpu.h>
+#include <linux/kthread.h>
 #include <linux/sysdev.h>
 #include <linux/workqueue.h>
 #include <asm/smp.h>
@@ -40,9 +41,19 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
        put_online_cpus();
 }
 
-static void __ref sclp_cpu_change_notify(struct work_struct *work)
+static int sclp_cpu_kthread(void *data)
 {
        smp_rescan_cpus();
+       return 0;
+}
+
+static void __ref sclp_cpu_change_notify(struct work_struct *work)
+{
+       /* Can't call smp_rescan_cpus() from  workqueue context since it may
+        * deadlock in case of cpu hotplug. So we have to create a kernel
+        * thread in order to call it.
+        */
+       kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan");
 }
 
 static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
@@ -74,10 +85,8 @@ static int __init sclp_conf_init(void)
        INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
 
        rc = sclp_register(&sclp_conf_register);
-       if (rc) {
-               printk(KERN_ERR TAG "failed to register (%d).\n", rc);
+       if (rc)
                return rc;
-       }
 
        if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
                printk(KERN_WARNING TAG "no configuration management.\n");
index 9f37456222e9bde478386ea921e7cba393c7fa2d..d887bd261d28e2029847213d1f6e017ed41dd06f 100644 (file)
@@ -27,6 +27,8 @@
 #define CPI_LENGTH_NAME 8
 #define CPI_LENGTH_LEVEL 16
 
+static DEFINE_MUTEX(sclp_cpi_mutex);
+
 struct cpi_evbuf {
        struct evbuf_header header;
        u8      id_format;
@@ -124,21 +126,15 @@ static int cpi_req(void)
        int response;
 
        rc = sclp_register(&sclp_cpi_event);
-       if (rc) {
-               printk(KERN_WARNING "cpi: could not register "
-                       "to hardware console.\n");
+       if (rc)
                goto out;
-       }
        if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) {
-               printk(KERN_WARNING "cpi: no control program "
-                       "identification support\n");
                rc = -EOPNOTSUPP;
                goto out_unregister;
        }
 
        req = cpi_prepare_req();
        if (IS_ERR(req)) {
-               printk(KERN_WARNING "cpi: could not allocate request\n");
                rc = PTR_ERR(req);
                goto out_unregister;
        }
@@ -148,10 +144,8 @@ static int cpi_req(void)
 
        /* Add request to sclp queue */
        rc = sclp_add_request(req);
-       if (rc) {
-               printk(KERN_WARNING "cpi: could not start request\n");
+       if (rc)
                goto out_free_req;
-       }
 
        wait_for_completion(&completion);
 
@@ -223,7 +217,12 @@ static void set_string(char *attr, const char *value)
 static ssize_t system_name_show(struct kobject *kobj,
                                struct kobj_attribute *attr, char *page)
 {
-       return snprintf(page, PAGE_SIZE, "%s\n", system_name);
+       int rc;
+
+       mutex_lock(&sclp_cpi_mutex);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", system_name);
+       mutex_unlock(&sclp_cpi_mutex);
+       return rc;
 }
 
 static ssize_t system_name_store(struct kobject *kobj,
@@ -237,7 +236,9 @@ static ssize_t system_name_store(struct kobject *kobj,
        if (rc)
                return rc;
 
+       mutex_lock(&sclp_cpi_mutex);
        set_string(system_name, buf);
+       mutex_unlock(&sclp_cpi_mutex);
 
        return len;
 }
@@ -248,7 +249,12 @@ static struct kobj_attribute system_name_attr =
 static ssize_t sysplex_name_show(struct kobject *kobj,
                                 struct kobj_attribute *attr, char *page)
 {
-       return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
+       int rc;
+
+       mutex_lock(&sclp_cpi_mutex);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
+       mutex_unlock(&sclp_cpi_mutex);
+       return rc;
 }
 
 static ssize_t sysplex_name_store(struct kobject *kobj,
@@ -262,7 +268,9 @@ static ssize_t sysplex_name_store(struct kobject *kobj,
        if (rc)
                return rc;
 
+       mutex_lock(&sclp_cpi_mutex);
        set_string(sysplex_name, buf);
+       mutex_unlock(&sclp_cpi_mutex);
 
        return len;
 }
@@ -273,7 +281,12 @@ static struct kobj_attribute sysplex_name_attr =
 static ssize_t system_type_show(struct kobject *kobj,
                                struct kobj_attribute *attr, char *page)
 {
-       return snprintf(page, PAGE_SIZE, "%s\n", system_type);
+       int rc;
+
+       mutex_lock(&sclp_cpi_mutex);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", system_type);
+       mutex_unlock(&sclp_cpi_mutex);
+       return rc;
 }
 
 static ssize_t system_type_store(struct kobject *kobj,
@@ -287,7 +300,9 @@ static ssize_t system_type_store(struct kobject *kobj,
        if (rc)
                return rc;
 
+       mutex_lock(&sclp_cpi_mutex);
        set_string(system_type, buf);
+       mutex_unlock(&sclp_cpi_mutex);
 
        return len;
 }
@@ -298,8 +313,11 @@ static struct kobj_attribute system_type_attr =
 static ssize_t system_level_show(struct kobject *kobj,
                                 struct kobj_attribute *attr, char *page)
 {
-       unsigned long long level = system_level;
+       unsigned long long level;
 
+       mutex_lock(&sclp_cpi_mutex);
+       level = system_level;
+       mutex_unlock(&sclp_cpi_mutex);
        return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
 }
 
@@ -320,8 +338,9 @@ static ssize_t system_level_store(struct kobject *kobj,
        if (*endp)
                return -EINVAL;
 
+       mutex_lock(&sclp_cpi_mutex);
        system_level = level;
-
+       mutex_unlock(&sclp_cpi_mutex);
        return len;
 }
 
@@ -334,7 +353,9 @@ static ssize_t set_store(struct kobject *kobj,
 {
        int rc;
 
+       mutex_lock(&sclp_cpi_mutex);
        rc = cpi_req();
+       mutex_unlock(&sclp_cpi_mutex);
        if (rc)
                return rc;
 
@@ -373,12 +394,16 @@ int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
        if (rc)
                return rc;
 
+       mutex_lock(&sclp_cpi_mutex);
        set_string(system_name, system);
        set_string(sysplex_name, sysplex);
        set_string(system_type, type);
        system_level = level;
 
-       return cpi_req();
+       rc = cpi_req();
+       mutex_unlock(&sclp_cpi_mutex);
+
+       return rc;
 }
 EXPORT_SYMBOL(sclp_cpi_set_data);
 
index 45ff25e787cbdad96659617eee981d6854e02700..84c191c1cd620fa1e5a723dcb060f9a8d4ae9175 100644 (file)
@@ -51,13 +51,7 @@ static struct sclp_register sclp_quiesce_event = {
 static int __init
 sclp_quiesce_init(void)
 {
-       int rc;
-
-       rc = sclp_register(&sclp_quiesce_event);
-       if (rc)
-               printk(KERN_WARNING "sclp: could not register quiesce handler "
-                      "(rc=%d)\n", rc);
-       return rc;
+       return sclp_register(&sclp_quiesce_event);
 }
 
 module_init(sclp_quiesce_init);
index da09781b32f7b0959441c2d6a4a544319d284edf..710af42603f80f7866b2d3be13e7ebaff14ce166 100644 (file)
@@ -19,8 +19,6 @@
 #include "sclp.h"
 #include "sclp_rw.h"
 
-#define SCLP_RW_PRINT_HEADER "sclp low level driver: "
-
 /*
  * The room for the SCCB (only for writing) is not equal to a pages size
  * (as it is specified as the maximum size in the SCLP documentation)
index 1c064976b32bd322a4e4554e9d335bf1cef71328..8b854857ba0733eb5a8a56a9451318a8d383603c 100644 (file)
@@ -239,10 +239,8 @@ int __init sclp_sdias_init(void)
        debug_register_view(sdias_dbf, &debug_sprintf_view);
        debug_set_level(sdias_dbf, 6);
        rc = sclp_register(&sclp_sdias_register);
-       if (rc) {
-               ERROR_MSG("sclp register failed\n");
+       if (rc)
                return rc;
-       }
        init_waitqueue_head(&sdias_wq);
        TRACE("init done\n");
        return 0;
index 40b11521cd20246ee308a34c92909f7c849058e9..434ba04b1309529e0e0959eea440a074085a5535 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -25,8 +24,6 @@
 #include "sclp_rw.h"
 #include "sclp_tty.h"
 
-#define SCLP_TTY_PRINT_HEADER "sclp tty driver: "
-
 /*
  * size of a buffer that collects single characters coming in
  * via sclp_tty_put_char()
@@ -50,8 +47,6 @@ static int sclp_tty_buffer_count;
 static struct sclp_buffer *sclp_ttybuf;
 /* Timer for delayed output of console messages. */
 static struct timer_list sclp_tty_timer;
-/* Waitqueue to wait for buffers to get empty. */
-static wait_queue_head_t sclp_tty_waitq;
 
 static struct tty_struct *sclp_tty;
 static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
@@ -59,19 +54,11 @@ static unsigned short int sclp_tty_chars_count;
 
 struct tty_driver *sclp_tty_driver;
 
-static struct sclp_ioctls sclp_ioctls;
-static struct sclp_ioctls sclp_ioctls_init =
-{
-       8,                      /* 1 hor. tab. = 8 spaces */
-       0,                      /* no echo of input by this driver */
-       80,                     /* 80 characters/line */
-       1,                      /* write after 1/10 s without final new line */
-       MAX_KMEM_PAGES,         /* quick fix: avoid __alloc_pages */
-       MAX_KMEM_PAGES,         /* take 32/64 pages from kernel memory, */
-       0,                      /* do not convert to lower case */
-       0x6c                    /* to seprate upper and lower case */
-                               /* ('%' in EBCDIC) */
-};
+static int sclp_tty_tolower;
+static int sclp_tty_columns = 80;
+
+#define SPACES_PER_TAB 8
+#define CASE_DELIMITER 0x6c /* to separate upper and lower case (% in EBCDIC) */
 
 /* This routine is called whenever we try to open a SCLP terminal. */
 static int
@@ -92,136 +79,6 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
        sclp_tty = NULL;
 }
 
-/* execute commands to control the i/o behaviour of the SCLP tty at runtime */
-static int
-sclp_tty_ioctl(struct tty_struct *tty, struct file * file,
-              unsigned int cmd, unsigned long arg)
-{
-       unsigned long flags;
-       unsigned int obuf;
-       int check;
-       int rc;
-
-       if (tty->flags & (1 << TTY_IO_ERROR))
-               return -EIO;
-       rc = 0;
-       check = 0;
-       switch (cmd) {
-       case TIOCSCLPSHTAB:
-               /* set width of horizontal tab  */
-               if (get_user(sclp_ioctls.htab, (unsigned short __user *) arg))
-                       rc = -EFAULT;
-               else
-                       check = 1;
-               break;
-       case TIOCSCLPGHTAB:
-               /* get width of horizontal tab  */
-               if (put_user(sclp_ioctls.htab, (unsigned short __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSECHO:
-               /* enable/disable echo of input */
-               if (get_user(sclp_ioctls.echo, (unsigned char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPGECHO:
-               /* Is echo of input enabled ?  */
-               if (put_user(sclp_ioctls.echo, (unsigned char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSCOLS:
-               /* set number of columns for output  */
-               if (get_user(sclp_ioctls.columns, (unsigned short __user *) arg))
-                       rc = -EFAULT;
-               else
-                       check = 1;
-               break;
-       case TIOCSCLPGCOLS:
-               /* get number of columns for output  */
-               if (put_user(sclp_ioctls.columns, (unsigned short __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSNL:
-               /* enable/disable writing without final new line character  */
-               if (get_user(sclp_ioctls.final_nl, (signed char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPGNL:
-               /* Is writing without final new line character enabled ?  */
-               if (put_user(sclp_ioctls.final_nl, (signed char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSOBUF:
-               /*
-                * set the maximum buffers size for output, will be rounded
-                * up to next 4kB boundary and stored as number of SCCBs
-                * (4kB Buffers) limitation: 256 x 4kB
-                */
-               if (get_user(obuf, (unsigned int __user *) arg) == 0) {
-                       if (obuf & 0xFFF)
-                               sclp_ioctls.max_sccb = (obuf >> 12) + 1;
-                       else
-                               sclp_ioctls.max_sccb = (obuf >> 12);
-               } else
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPGOBUF:
-               /* get the maximum buffers size for output  */
-               obuf = sclp_ioctls.max_sccb << 12;
-               if (put_user(obuf, (unsigned int __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPGKBUF:
-               /* get the number of buffers got from kernel at startup */
-               if (put_user(sclp_ioctls.kmem_sccb, (unsigned short __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSCASE:
-               /* enable/disable conversion from upper to lower case */
-               if (get_user(sclp_ioctls.tolower, (unsigned char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPGCASE:
-               /* Is conversion from upper to lower case of input enabled? */
-               if (put_user(sclp_ioctls.tolower, (unsigned char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSDELIM:
-               /*
-                * set special character used for separating upper and
-                * lower case, 0x00 disables this feature
-                */
-               if (get_user(sclp_ioctls.delim, (unsigned char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPGDELIM:
-               /*
-                * get special character used for separating upper and
-                * lower case, 0x00 disables this feature
-                */
-               if (put_user(sclp_ioctls.delim, (unsigned char __user *) arg))
-                       rc = -EFAULT;
-               break;
-       case TIOCSCLPSINIT:
-               /* set initial (default) sclp ioctls  */
-               sclp_ioctls = sclp_ioctls_init;
-               check = 1;
-               break;
-       default:
-               rc = -ENOIOCTLCMD;
-               break;
-       }
-       if (check) {
-               spin_lock_irqsave(&sclp_tty_lock, flags);
-               if (sclp_ttybuf != NULL) {
-                       sclp_set_htab(sclp_ttybuf, sclp_ioctls.htab);
-                       sclp_set_columns(sclp_ttybuf, sclp_ioctls.columns);
-               }
-               spin_unlock_irqrestore(&sclp_tty_lock, flags);
-       }
-       return rc;
-}
-
 /*
  * This routine returns the numbers of characters the tty driver
  * will accept for queuing to be written.  This number is subject
@@ -268,7 +125,6 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
                                            struct sclp_buffer, list);
                spin_unlock_irqrestore(&sclp_tty_lock, flags);
        } while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
-       wake_up(&sclp_tty_waitq);
        /* check if the tty needs a wake up call */
        if (sclp_tty != NULL) {
                tty_wakeup(sclp_tty);
@@ -316,37 +172,37 @@ sclp_tty_timeout(unsigned long data)
 /*
  * Write a string to the sclp tty.
  */
-static void
-sclp_tty_write_string(const unsigned char *str, int count)
+static int sclp_tty_write_string(const unsigned char *str, int count, int may_fail)
 {
        unsigned long flags;
        void *page;
        int written;
+       int overall_written;
        struct sclp_buffer *buf;
 
        if (count <= 0)
-               return;
+               return 0;
+       overall_written = 0;
        spin_lock_irqsave(&sclp_tty_lock, flags);
        do {
                /* Create a sclp output buffer if none exists yet */
                if (sclp_ttybuf == NULL) {
                        while (list_empty(&sclp_tty_pages)) {
                                spin_unlock_irqrestore(&sclp_tty_lock, flags);
-                               if (in_interrupt())
-                                       sclp_sync_wait();
+                               if (may_fail)
+                                       goto out;
                                else
-                                       wait_event(sclp_tty_waitq,
-                                               !list_empty(&sclp_tty_pages));
+                                       sclp_sync_wait();
                                spin_lock_irqsave(&sclp_tty_lock, flags);
                        }
                        page = sclp_tty_pages.next;
                        list_del((struct list_head *) page);
-                       sclp_ttybuf = sclp_make_buffer(page,
-                                                      sclp_ioctls.columns,
-                                                      sclp_ioctls.htab);
+                       sclp_ttybuf = sclp_make_buffer(page, sclp_tty_columns,
+                                                      SPACES_PER_TAB);
                }
                /* try to write the string to the current output buffer */
                written = sclp_write(sclp_ttybuf, str, count);
+               overall_written += written;
                if (written == count)
                        break;
                /*
@@ -363,27 +219,17 @@ sclp_tty_write_string(const unsigned char *str, int count)
                count -= written;
        } while (count > 0);
        /* Setup timer to output current console buffer after 1/10 second */
-       if (sclp_ioctls.final_nl) {
-               if (sclp_ttybuf != NULL &&
-                   sclp_chars_in_buffer(sclp_ttybuf) != 0 &&
-                   !timer_pending(&sclp_tty_timer)) {
-                       init_timer(&sclp_tty_timer);
-                       sclp_tty_timer.function = sclp_tty_timeout;
-                       sclp_tty_timer.data = 0UL;
-                       sclp_tty_timer.expires = jiffies + HZ/10;
-                       add_timer(&sclp_tty_timer);
-               }
-       } else {
-               if (sclp_ttybuf != NULL &&
-                   sclp_chars_in_buffer(sclp_ttybuf) != 0) {
-                       buf = sclp_ttybuf;
-                       sclp_ttybuf = NULL;
-                       spin_unlock_irqrestore(&sclp_tty_lock, flags);
-                       __sclp_ttybuf_emit(buf);
-                       spin_lock_irqsave(&sclp_tty_lock, flags);
-               }
+       if (sclp_ttybuf && sclp_chars_in_buffer(sclp_ttybuf) &&
+           !timer_pending(&sclp_tty_timer)) {
+               init_timer(&sclp_tty_timer);
+               sclp_tty_timer.function = sclp_tty_timeout;
+               sclp_tty_timer.data = 0UL;
+               sclp_tty_timer.expires = jiffies + HZ/10;
+               add_timer(&sclp_tty_timer);
        }
        spin_unlock_irqrestore(&sclp_tty_lock, flags);
+out:
+       return overall_written;
 }
 
 /*
@@ -395,11 +241,10 @@ static int
 sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        if (sclp_tty_chars_count > 0) {
-               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
+               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
                sclp_tty_chars_count = 0;
        }
-       sclp_tty_write_string(buf, count);
-       return count;
+       return sclp_tty_write_string(buf, count, 1);
 }
 
 /*
@@ -417,9 +262,10 @@ sclp_tty_put_char(struct tty_struct *tty, unsigned char ch)
 {
        sclp_tty_chars[sclp_tty_chars_count++] = ch;
        if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {
-               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
+               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
                sclp_tty_chars_count = 0;
-       } return 1;
+       }
+       return 1;
 }
 
 /*
@@ -430,7 +276,7 @@ static void
 sclp_tty_flush_chars(struct tty_struct *tty)
 {
        if (sclp_tty_chars_count > 0) {
-               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
+               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
                sclp_tty_chars_count = 0;
        }
 }
@@ -469,7 +315,7 @@ static void
 sclp_tty_flush_buffer(struct tty_struct *tty)
 {
        if (sclp_tty_chars_count > 0) {
-               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
+               sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0);
                sclp_tty_chars_count = 0;
        }
 }
@@ -517,9 +363,7 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
  * modifiy original string,
  * returns length of resulting string
  */
-static int
-sclp_switch_cases(unsigned char *buf, int count,
-                 unsigned char delim, int tolower)
+static int sclp_switch_cases(unsigned char *buf, int count)
 {
        unsigned char *ip, *op;
        int toggle;
@@ -529,9 +373,9 @@ sclp_switch_cases(unsigned char *buf, int count,
        ip = op = buf;
        while (count-- > 0) {
                /* compare with special character */
-               if (*ip == delim) {
+               if (*ip == CASE_DELIMITER) {
                        /* followed by another special character? */
-                       if (count && ip[1] == delim) {
+                       if (count && ip[1] == CASE_DELIMITER) {
                                /*
                                 * ... then put a single copy of the special
                                 * character to the output string
@@ -550,7 +394,7 @@ sclp_switch_cases(unsigned char *buf, int count,
                        /* not the special character */
                        if (toggle)
                                /* but case switching is on */
-                               if (tolower)
+                               if (sclp_tty_tolower)
                                        /* switch to uppercase */
                                        *op++ = _ebc_toupper[(int) *ip++];
                                else
@@ -570,30 +414,12 @@ sclp_get_input(unsigned char *start, unsigned char *end)
        int count;
 
        count = end - start;
-       /*
-        * if set in ioctl convert EBCDIC to lower case
-        * (modify original input in SCCB)
-        */
-       if (sclp_ioctls.tolower)
+       if (sclp_tty_tolower)
                EBC_TOLOWER(start, count);
-
-       /*
-        * if set in ioctl find out characters in lower or upper case
-        * (depends on current case) separated by a special character,
-        * works on EBCDIC
-        */
-       if (sclp_ioctls.delim)
-               count = sclp_switch_cases(start, count,
-                                         sclp_ioctls.delim,
-                                         sclp_ioctls.tolower);
-
+       count = sclp_switch_cases(start, count);
        /* convert EBCDIC to ASCII (modify original input in SCCB) */
        sclp_ebcasc_str(start, count);
 
-       /* if set in ioctl write operators input to console  */
-       if (sclp_ioctls.echo)
-               sclp_tty_write(sclp_tty, start, count);
-
        /* transfer input to high level driver */
        sclp_tty_input(start, count);
 }
@@ -717,7 +543,6 @@ static const struct tty_operations sclp_ops = {
        .write_room = sclp_tty_write_room,
        .chars_in_buffer = sclp_tty_chars_in_buffer,
        .flush_buffer = sclp_tty_flush_buffer,
-       .ioctl = sclp_tty_ioctl,
 };
 
 static int __init
@@ -736,9 +561,6 @@ sclp_tty_init(void)
 
        rc = sclp_rw_init();
        if (rc) {
-               printk(KERN_ERR SCLP_TTY_PRINT_HEADER
-                      "could not register tty - "
-                      "sclp_rw_init returned %d\n", rc);
                put_tty_driver(driver);
                return rc;
        }
@@ -754,7 +576,6 @@ sclp_tty_init(void)
        }
        INIT_LIST_HEAD(&sclp_tty_outqueue);
        spin_lock_init(&sclp_tty_lock);
-       init_waitqueue_head(&sclp_tty_waitq);
        init_timer(&sclp_tty_timer);
        sclp_ttybuf = NULL;
        sclp_tty_buffer_count = 0;
@@ -763,11 +584,10 @@ sclp_tty_init(void)
                 * save 4 characters for the CPU number
                 * written at start of each line by VM/CP
                 */
-               sclp_ioctls_init.columns = 76;
+               sclp_tty_columns = 76;
                /* case input lines to lowercase */
-               sclp_ioctls_init.tolower = 1;
+               sclp_tty_tolower = 1;
        }
-       sclp_ioctls = sclp_ioctls_init;
        sclp_tty_chars_count = 0;
        sclp_tty = NULL;
 
@@ -792,9 +612,6 @@ sclp_tty_init(void)
        tty_set_operations(driver, &sclp_ops);
        rc = tty_register_driver(driver);
        if (rc) {
-               printk(KERN_ERR SCLP_TTY_PRINT_HEADER
-                      "could not register tty - "
-                      "tty_register_driver returned %d\n", rc);
                put_tty_driver(driver);
                return rc;
        }
index 0ce2c1fc5340674bb1826a44028b8c1b9ec00bb6..4b965b22fecd7a24e375059d8cb0aa5b7f5c5d1b 100644 (file)
 #ifndef __SCLP_TTY_H__
 #define __SCLP_TTY_H__
 
-#include <linux/ioctl.h>
-#include <linux/termios.h>
 #include <linux/tty_driver.h>
 
-/* This is the type of data structures storing sclp ioctl setting. */
-struct sclp_ioctls {
-       unsigned short htab;
-       unsigned char echo;
-       unsigned short columns;
-       unsigned char final_nl;
-       unsigned short max_sccb;
-       unsigned short kmem_sccb;       /* can't be modified at run time */
-       unsigned char tolower;
-       unsigned char delim;
-};
-
-/* must be unique, FIXME: must be added in Documentation/ioctl_number.txt */
-#define SCLP_IOCTL_LETTER 'B'
-
-/* set width of horizontal tabulator */
-#define TIOCSCLPSHTAB  _IOW(SCLP_IOCTL_LETTER, 0, unsigned short)
-/* enable/disable echo of input (independent from line discipline) */
-#define TIOCSCLPSECHO  _IOW(SCLP_IOCTL_LETTER, 1, unsigned char)
-/* set number of colums for output */
-#define TIOCSCLPSCOLS  _IOW(SCLP_IOCTL_LETTER, 2, unsigned short)
-/* enable/disable writing without final new line character */
-#define TIOCSCLPSNL    _IOW(SCLP_IOCTL_LETTER, 4, signed char)
-/* set the maximum buffers size for output, rounded up to next 4kB boundary */
-#define TIOCSCLPSOBUF  _IOW(SCLP_IOCTL_LETTER, 5, unsigned short)
-/* set initial (default) sclp ioctls */
-#define TIOCSCLPSINIT  _IO(SCLP_IOCTL_LETTER, 6)
-/* enable/disable conversion from upper to lower case of input */
-#define TIOCSCLPSCASE  _IOW(SCLP_IOCTL_LETTER, 7, unsigned char)
-/* set special character used for separating upper and lower case, */
-/* 0x00 disables this feature */
-#define TIOCSCLPSDELIM _IOW(SCLP_IOCTL_LETTER, 9, unsigned char)
-
-/* get width of horizontal tabulator */
-#define TIOCSCLPGHTAB  _IOR(SCLP_IOCTL_LETTER, 10, unsigned short)
-/* Is echo of input enabled ? (independent from line discipline) */
-#define TIOCSCLPGECHO  _IOR(SCLP_IOCTL_LETTER, 11, unsigned char)
-/* get number of colums for output */
-#define TIOCSCLPGCOLS  _IOR(SCLP_IOCTL_LETTER, 12, unsigned short)
-/* Is writing without final new line character enabled ? */
-#define TIOCSCLPGNL    _IOR(SCLP_IOCTL_LETTER, 14, signed char)
-/* get the maximum buffers size for output */
-#define TIOCSCLPGOBUF  _IOR(SCLP_IOCTL_LETTER, 15, unsigned short)
-/* Is conversion from upper to lower case of input enabled ? */
-#define TIOCSCLPGCASE  _IOR(SCLP_IOCTL_LETTER, 17, unsigned char)
-/* get special character used for separating upper and lower case, */
-/* 0x00 disables this feature */
-#define TIOCSCLPGDELIM _IOR(SCLP_IOCTL_LETTER, 19, unsigned char)
-/* get the number of buffers/pages got from kernel at startup */
-#define TIOCSCLPGKBUF  _IOR(SCLP_IOCTL_LETTER, 20, unsigned short)
-
 extern struct tty_driver *sclp_tty_driver;
 
 #endif /* __SCLP_TTY_H__ */
index 3e577f655b18dec1cd7cf24cdf3b88c155bc6783..ad51738c4261973a7f4fb8b74296dc5dcc17bb85 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/uaccess.h>
 #include "sclp.h"
 
-#define SCLP_VT220_PRINT_HEADER        "sclp vt220 tty driver: "
 #define SCLP_VT220_MAJOR               TTY_MAJOR
 #define SCLP_VT220_MINOR               65
 #define SCLP_VT220_DRIVER_NAME         "sclp_vt220"
@@ -82,8 +81,8 @@ static struct sclp_vt220_request *sclp_vt220_current_request;
 /* Number of characters in current request buffer */
 static int sclp_vt220_buffered_chars;
 
-/* Flag indicating whether this driver has already been initialized */
-static int sclp_vt220_initialized = 0;
+/* Counter controlling core driver initialization. */
+static int __initdata sclp_vt220_init_count;
 
 /* Flag indicating that sclp_vt220_current_request should really
  * have been already queued but wasn't because the SCLP was processing
@@ -609,10 +608,8 @@ sclp_vt220_flush_buffer(struct tty_struct *tty)
        sclp_vt220_emit_current();
 }
 
-/*
- * Initialize all relevant components and register driver with system.
- */
-static void __init __sclp_vt220_cleanup(void)
+/* Release allocated pages. */
+static void __init __sclp_vt220_free_pages(void)
 {
        struct list_head *page, *p;
 
@@ -623,21 +620,30 @@ static void __init __sclp_vt220_cleanup(void)
                else
                        free_bootmem((unsigned long) page, PAGE_SIZE);
        }
-       if (!list_empty(&sclp_vt220_register.list))
-               sclp_unregister(&sclp_vt220_register);
-       sclp_vt220_initialized = 0;
 }
 
-static int __init __sclp_vt220_init(void)
+/* Release memory and unregister from sclp core. Controlled by init counting -
+ * only the last invoker will actually perform these actions. */
+static void __init __sclp_vt220_cleanup(void)
+{
+       sclp_vt220_init_count--;
+       if (sclp_vt220_init_count != 0)
+               return;
+       sclp_unregister(&sclp_vt220_register);
+       __sclp_vt220_free_pages();
+}
+
+/* Allocate buffer pages and register with sclp core. Controlled by init
+ * counting - only the first invoker will actually perform these actions. */
+static int __init __sclp_vt220_init(int num_pages)
 {
        void *page;
        int i;
-       int num_pages;
        int rc;
 
-       if (sclp_vt220_initialized)
+       sclp_vt220_init_count++;
+       if (sclp_vt220_init_count != 1)
                return 0;
-       sclp_vt220_initialized = 1;
        spin_lock_init(&sclp_vt220_lock);
        INIT_LIST_HEAD(&sclp_vt220_empty);
        INIT_LIST_HEAD(&sclp_vt220_outqueue);
@@ -649,24 +655,22 @@ static int __init __sclp_vt220_init(void)
        sclp_vt220_flush_later = 0;
 
        /* Allocate pages for output buffering */
-       num_pages = slab_is_available() ? MAX_KMEM_PAGES : MAX_CONSOLE_PAGES;
        for (i = 0; i < num_pages; i++) {
                if (slab_is_available())
                        page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
                else
                        page = alloc_bootmem_low_pages(PAGE_SIZE);
                if (!page) {
-                       __sclp_vt220_cleanup();
-                       return -ENOMEM;
+                       rc = -ENOMEM;
+                       goto out;
                }
                list_add_tail((struct list_head *) page, &sclp_vt220_empty);
        }
        rc = sclp_register(&sclp_vt220_register);
+out:
        if (rc) {
-               printk(KERN_ERR SCLP_VT220_PRINT_HEADER
-                      "could not register vt220 - "
-                      "sclp_register returned %d\n", rc);
-               __sclp_vt220_cleanup();
+               __sclp_vt220_free_pages();
+               sclp_vt220_init_count--;
        }
        return rc;
 }
@@ -689,15 +693,13 @@ static int __init sclp_vt220_tty_init(void)
 {
        struct tty_driver *driver;
        int rc;
-       int cleanup;
 
        /* Note: we're not testing for CONSOLE_IS_SCLP here to preserve
         * symmetry between VM and LPAR systems regarding ttyS1. */
        driver = alloc_tty_driver(1);
        if (!driver)
                return -ENOMEM;
-       cleanup = !sclp_vt220_initialized;
-       rc = __sclp_vt220_init();
+       rc = __sclp_vt220_init(MAX_KMEM_PAGES);
        if (rc)
                goto out_driver;
 
@@ -713,18 +715,13 @@ static int __init sclp_vt220_tty_init(void)
        tty_set_operations(driver, &sclp_vt220_ops);
 
        rc = tty_register_driver(driver);
-       if (rc) {
-               printk(KERN_ERR SCLP_VT220_PRINT_HEADER
-                      "could not register tty - "
-                      "tty_register_driver returned %d\n", rc);
+       if (rc)
                goto out_init;
-       }
        sclp_vt220_driver = driver;
        return 0;
 
 out_init:
-       if (cleanup)
-               __sclp_vt220_cleanup();
+       __sclp_vt220_cleanup();
 out_driver:
        put_tty_driver(driver);
        return rc;
@@ -773,10 +770,9 @@ sclp_vt220_con_init(void)
 {
        int rc;
 
-       INIT_LIST_HEAD(&sclp_vt220_register.list);
        if (!CONSOLE_IS_SCLP)
                return 0;
-       rc = __sclp_vt220_init();
+       rc = __sclp_vt220_init(MAX_CONSOLE_PAGES);
        if (rc)
                return rc;
        /* Attach linux console */
index 874adf365e467a4f9d1bce3c89bd27b718a54461..22ca34361ed7711e15eb9a7c5688970aab46b81d 100644 (file)
@@ -196,7 +196,7 @@ tape_34xx_erp_retry(struct tape_request *request)
 static int
 tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb)
 {
-       if (irb->scsw.dstat == 0x85 /* READY */) {
+       if (irb->scsw.cmd.dstat == 0x85) { /* READY */
                /* A medium was inserted in the drive. */
                DBF_EVENT(6, "xuud med\n");
                tape_34xx_delete_sbid_from(device, 0);
@@ -844,22 +844,22 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request,
        if (request == NULL)
                return tape_34xx_unsolicited_irq(device, irb);
 
-       if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) &&
-           (irb->scsw.dstat & DEV_STAT_DEV_END) &&
+       if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
+           (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
            (request->op == TO_WRI)) {
                /* Write at end of volume */
                PRINT_INFO("End of volume\n"); /* XXX */
                return tape_34xx_erp_failed(request, -ENOSPC);
        }
 
-       if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
+       if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
                return tape_34xx_unit_check(device, request, irb);
 
-       if (irb->scsw.dstat & DEV_STAT_DEV_END) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
                /*
                 * A unit exception occurs on skipping over a tapemark block.
                 */
-               if (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) {
+               if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) {
                        if (request->op == TO_BSB || request->op == TO_FSB)
                                request->rescnt++;
                        else
index 42ce7915fc5d7cc1bce71aaa60c867f12cb16894..839987618ffd8d545538626733b4c0ca1205c8ce 100644 (file)
@@ -837,13 +837,13 @@ tape_3590_erp_retry(struct tape_device *device, struct tape_request *request,
 static int
 tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
 {
-       if (irb->scsw.dstat == DEV_STAT_CHN_END)
+       if (irb->scsw.cmd.dstat == DEV_STAT_CHN_END)
                /* Probably result of halt ssch */
                return TAPE_IO_PENDING;
-       else if (irb->scsw.dstat == 0x85)
+       else if (irb->scsw.cmd.dstat == 0x85)
                /* Device Ready */
                DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
-       else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+       else if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
                tape_3590_schedule_work(device, TO_READ_ATTMSG);
        } else {
                DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
@@ -1515,18 +1515,19 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request,
        if (request == NULL)
                return tape_3590_unsolicited_irq(device, irb);
 
-       if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) &&
-           (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) {
+       if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
+           (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
+           (request->op == TO_WRI)) {
                /* Write at end of volume */
                DBF_EVENT(2, "End of volume\n");
                return tape_3590_erp_failed(device, request, irb, -ENOSPC);
        }
 
-       if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
+       if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
                return tape_3590_unit_check(device, request, irb);
 
-       if (irb->scsw.dstat & DEV_STAT_DEV_END) {
-               if (irb->scsw.dstat == DEV_STAT_UNIT_EXCEP) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
+               if (irb->scsw.cmd.dstat == DEV_STAT_UNIT_EXCEP) {
                        if (request->op == TO_FSB || request->op == TO_BSB)
                                request->rescnt++;
                        else
@@ -1536,12 +1537,12 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request,
                return tape_3590_done(device, request);
        }
 
-       if (irb->scsw.dstat & DEV_STAT_CHN_END) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) {
                DBF_EVENT(2, "cannel end\n");
                return TAPE_IO_PENDING;
        }
 
-       if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
                DBF_EVENT(2, "Unit Attention when busy..\n");
                return TAPE_IO_PENDING;
        }
index c20e3c548343aa7f3b43c56d57d94f1ab6c5e441..181a5441af16f92dad8b1c0bba954ca5bbefca51 100644 (file)
@@ -839,7 +839,7 @@ tape_dump_sense(struct tape_device* device, struct tape_request *request,
 
        PRINT_INFO("-------------------------------------------------\n");
        PRINT_INFO("DSTAT : %02x  CSTAT: %02x   CPA: %04x\n",
-                  irb->scsw.dstat, irb->scsw.cstat, irb->scsw.cpa);
+                  irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa);
        PRINT_INFO("DEVICE: %s\n", device->cdev->dev.bus_id);
        if (request != NULL)
                PRINT_INFO("OP    : %s\n", tape_op_verbose[request->op]);
@@ -867,7 +867,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,
        else
                op = "---";
        DBF_EVENT(3, "DSTAT : %02x   CSTAT: %02x\n",
-                 irb->scsw.dstat,irb->scsw.cstat);
+                 irb->scsw.cmd.dstat, irb->scsw.cmd.cstat);
        DBF_EVENT(3, "DEVICE: %08x OP\t: %s\n", device->cdev_id, op);
        sptr = (unsigned int *) irb->ecw;
        DBF_EVENT(3, "%08x %08x\n", sptr[0], sptr[1]);
@@ -1083,10 +1083,11 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
         * error might still apply. So we just schedule the request to be
         * started later.
         */
-       if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
+       if (irb->scsw.cmd.cc != 0 &&
+           (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
            (request->status == TAPE_REQUEST_IN_IO)) {
                DBF_EVENT(3,"(%08x): deferred cc=%i, fctl=%i. restarting\n",
-                       device->cdev_id, irb->scsw.cc, irb->scsw.fctl);
+                       device->cdev_id, irb->scsw.cmd.cc, irb->scsw.cmd.fctl);
                request->status = TAPE_REQUEST_QUEUED;
                schedule_delayed_work(&device->tape_dnr, HZ);
                return;
@@ -1094,8 +1095,8 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
 
        /* May be an unsolicited irq */
        if(request != NULL)
-               request->rescnt = irb->scsw.count;
-       else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) &&
+               request->rescnt = irb->scsw.cmd.count;
+       else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) &&
                 !list_empty(&device->req_queue)) {
                /* Not Ready to Ready after long busy ? */
                struct tape_request *req;
@@ -1111,7 +1112,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                        return;
                }
        }
-       if (irb->scsw.dstat != 0x0c) {
+       if (irb->scsw.cmd.dstat != 0x0c) {
                /* Set the 'ONLINE' flag depending on sense byte 1 */
                if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE)
                        device->tape_generic_status |= GMT_ONLINE(~0);
index 5043150019ac0788e91d4a42ee1d49955c99d527..a7fe6302c9820c3790f3c14bffb4f0aee4b35679 100644 (file)
@@ -663,7 +663,7 @@ static int
 tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
 {
        /* Handle ATTN. Schedule tasklet to read aid. */
-       if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
                if (!tp->throttle)
                        tty3270_issue_read(tp, 0);
                else
@@ -671,11 +671,11 @@ tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
        }
 
        if (rq) {
-               if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
+               if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
                        rq->rc = -EIO;
                else
                        /* Normal end. Copy residual count. */
-                       rq->rescnt = irb->scsw.count;
+                       rq->rescnt = irb->scsw.cmd.count;
        }
        return RAW3270_IO_DONE;
 }
@@ -1792,15 +1792,12 @@ static int __init tty3270_init(void)
        tty_set_operations(driver, &tty3270_ops);
        ret = tty_register_driver(driver);
        if (ret) {
-               printk(KERN_ERR "tty3270 registration failed with %d\n", ret);
                put_tty_driver(driver);
                return ret;
        }
        tty3270_driver = driver;
        ret = raw3270_register_notifier(tty3270_notifier);
        if (ret) {
-               printk(KERN_ERR "tty3270 notifier registration failed "
-                      "with %d\n", ret);
                put_tty_driver(driver);
                return ret;
 
index 2f419b0ea628bf1dd47ca0385f54f95bbf808235..401ea84b3059f3e3e3f1a025233c23f3e9e78b8c 100644 (file)
@@ -61,30 +61,24 @@ static int vmcp_release(struct inode *inode, struct file *file)
 static ssize_t
 vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos)
 {
-       size_t tocopy;
+       ssize_t ret;
+       size_t size;
        struct vmcp_session *session;
 
-       session = (struct vmcp_session *)file->private_data;
+       session = file->private_data;
        if (mutex_lock_interruptible(&session->mutex))
                return -ERESTARTSYS;
        if (!session->response) {
                mutex_unlock(&session->mutex);
                return 0;
        }
-       if (*ppos > session->resp_size) {
-               mutex_unlock(&session->mutex);
-               return 0;
-       }
-       tocopy = min(session->resp_size - (size_t) (*ppos), count);
-       tocopy = min(tocopy, session->bufsize - (size_t) (*ppos));
+       size = min_t(size_t, session->resp_size, session->bufsize);
+       ret = simple_read_from_buffer(buff, count, ppos,
+                                       session->response, size);
 
-       if (copy_to_user(buff, session->response + (*ppos), tocopy)) {
-               mutex_unlock(&session->mutex);
-               return -EFAULT;
-       }
        mutex_unlock(&session->mutex);
-       *ppos += tocopy;
-       return tocopy;
+
+       return ret;
 }
 
 static ssize_t
@@ -198,27 +192,23 @@ static int __init vmcp_init(void)
                PRINT_WARN("z/VM CP interface is only available under z/VM\n");
                return -ENODEV;
        }
+
        vmcp_debug = debug_register("vmcp", 1, 1, 240);
-       if (!vmcp_debug) {
-               PRINT_ERR("z/VM CP interface not loaded. Could not register "
-                          "debug feature\n");
+       if (!vmcp_debug)
                return -ENOMEM;
-       }
+
        ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view);
        if (ret) {
-               PRINT_ERR("z/VM CP interface not loaded. Could not register "
-                         "debug feature view. Error code: %d\n", ret);
                debug_unregister(vmcp_debug);
                return ret;
        }
+
        ret = misc_register(&vmcp_dev);
        if (ret) {
-               PRINT_ERR("z/VM CP interface not loaded. Could not register "
-                          "misc device. Error code: %d\n", ret);
                debug_unregister(vmcp_debug);
                return ret;
        }
-       PRINT_INFO("z/VM CP interface loaded\n");
+
        return 0;
 }
 
@@ -226,7 +216,6 @@ static void __exit vmcp_exit(void)
 {
        misc_deregister(&vmcp_dev);
        debug_unregister(vmcp_debug);
-       PRINT_INFO("z/VM CP interface unloaded.\n");
 }
 
 module_init(vmcp_init);
index 2c2428cc05d866efe26b9c288331ab6459afdeb0..a246bc73ae6430b5761a47ccc90305c7564da9e4 100644 (file)
@@ -216,9 +216,7 @@ static int vmlogrdr_get_recording_class_AB(void)
        char *tail;
        int len,i;
 
-       printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command);
        cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
-       printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response);
        len = strnlen(cp_response,sizeof(cp_response));
        // now the parsing
        tail=strnchr(cp_response,len,'=');
@@ -268,11 +266,7 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
                         logptr->recording_name,
                         qid_string);
 
-               printk (KERN_DEBUG "vmlogrdr: recording command: %s\n",
-                       cp_command);
                cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
-               printk (KERN_DEBUG "vmlogrdr: recording response: %s",
-                       cp_response);
        }
 
        memset(cp_command, 0x00, sizeof(cp_command));
@@ -282,10 +276,7 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
                onoff,
                qid_string);
 
-       printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
        cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
-       printk (KERN_DEBUG "vmlogrdr: recording response: %s",
-               cp_response);
        /* The recording command will usually answer with 'Command complete'
         * on success, but when the specific service was never connected
         * before then there might be an additional informational message
@@ -567,10 +558,7 @@ static ssize_t vmlogrdr_purge_store(struct device * dev,
                         "RECORDING %s PURGE ",
                         priv->recording_name);
 
-       printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
        cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
-       printk (KERN_DEBUG "vmlogrdr: recording response: %s",
-               cp_response);
 
        return count;
 }
@@ -682,28 +670,20 @@ static int vmlogrdr_register_driver(void)
 
        /* Register with iucv driver */
        ret = iucv_register(&vmlogrdr_iucv_handler, 1);
-       if (ret) {
-               printk (KERN_ERR "vmlogrdr: failed to register with "
-                       "iucv driver\n");
+       if (ret)
                goto out;
-       }
 
        ret = driver_register(&vmlogrdr_driver);
-       if (ret) {
-               printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
+       if (ret)
                goto out_iucv;
-       }
 
        ret = driver_create_file(&vmlogrdr_driver,
                                 &driver_attr_recording_status);
-       if (ret) {
-               printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
+       if (ret)
                goto out_driver;
-       }
 
        vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
        if (IS_ERR(vmlogrdr_class)) {
-               printk(KERN_ERR "vmlogrdr: failed to create class.\n");
                ret = PTR_ERR(vmlogrdr_class);
                vmlogrdr_class = NULL;
                goto out_attr;
@@ -871,12 +851,10 @@ static int __init vmlogrdr_init(void)
        rc = vmlogrdr_register_cdev(dev);
        if (rc)
                goto cleanup;
-       printk (KERN_INFO "vmlogrdr: driver loaded\n");
        return 0;
 
 cleanup:
        vmlogrdr_cleanup();
-       printk (KERN_ERR "vmlogrdr: driver not loaded.\n");
        return rc;
 }
 
@@ -884,7 +862,6 @@ cleanup:
 static void __exit vmlogrdr_exit(void)
 {
        vmlogrdr_cleanup();
-       printk (KERN_INFO "vmlogrdr: driver unloaded\n");
        return;
 }
 
index 83ae9a852f00c2dc5c4e2fc9be7eb81e974770de..49cba9effe892d2a1638a67a2ade3b4dddfc5550 100644 (file)
@@ -277,7 +277,8 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
        struct urdev *urd;
 
        TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n",
-             intparm, irb->scsw.cstat, irb->scsw.dstat, irb->scsw.count);
+             intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat,
+             irb->scsw.cmd.count);
 
        if (!intparm) {
                TRACE("ur_int_handler: unsolicited interrupt\n");
@@ -288,7 +289,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
        /* On special conditions irb is an error pointer */
        if (IS_ERR(irb))
                urd->io_request_rc = PTR_ERR(irb);
-       else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+       else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
                urd->io_request_rc = 0;
        else
                urd->io_request_rc = -EIO;
index 19f8389291b62c3f13b76eafde98ae03f1677666..56b3eab019cbddde76219ec3fb0bfa50406089aa 100644 (file)
@@ -92,23 +92,15 @@ static int vmwdt_keepalive(void)
 
        func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init;
        ret = __diag288(func, vmwdt_interval, ebc_cmd, len);
+       WARN_ON(ret != 0);
        kfree(ebc_cmd);
-
-       if (ret) {
-               printk(KERN_WARNING "%s: problem setting interval %d, "
-                       "cmd %s\n", __func__, vmwdt_interval,
-                       vmwdt_cmd);
-       }
        return ret;
 }
 
 static int vmwdt_disable(void)
 {
        int ret = __diag288(wdt_cancel, 0, "", 0);
-       if (ret) {
-               printk(KERN_WARNING "%s: problem disabling watchdog\n",
-                       __func__);
-       }
+       WARN_ON(ret != 0);
        return ret;
 }
 
@@ -121,10 +113,8 @@ static int __init vmwdt_probe(void)
        static char __initdata ebc_begin[] = {
                194, 197, 199, 201, 213
        };
-       if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) {
-               printk(KERN_INFO "z/VM watchdog not available\n");
+       if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0)
                return -EINVAL;
-       }
        return vmwdt_disable();
 }
 
index bbbd14e9d48f8a17a6bb9f3efd566d7781ff71c0..047dd92ae804505ed9e363e526060b1822a6f102 100644 (file)
@@ -223,12 +223,10 @@ static int __init init_cpu_info(enum arch_id arch)
        /* get info for boot cpu from lowcore, stored in the HSA */
 
        sa = kmalloc(sizeof(*sa), GFP_KERNEL);
-       if (!sa) {
-               ERROR_MSG("kmalloc failed: %s: %i\n",__func__, __LINE__);
+       if (!sa)
                return -ENOMEM;
-       }
        if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) {
-               ERROR_MSG("could not copy from HSA\n");
+               TRACE("could not copy from HSA\n");
                kfree(sa);
                return -EIO;
        }
@@ -511,6 +509,8 @@ static void __init set_s390x_lc_mask(union save_area *map)
  */
 static int __init sys_info_init(enum arch_id arch)
 {
+       int rc;
+
        switch (arch) {
        case ARCH_S390X:
                MSG("DETECTED 'S390X (64 bit) OS'\n");
@@ -529,10 +529,9 @@ static int __init sys_info_init(enum arch_id arch)
                return -EINVAL;
        }
        sys_info.arch = arch;
-       if (init_cpu_info(arch)) {
-               ERROR_MSG("get cpu info failed\n");
-               return -ENOMEM;
-       }
+       rc = init_cpu_info(arch);
+       if (rc)
+               return rc;
        sys_info.mem_size = real_memory_size;
 
        return 0;
@@ -544,12 +543,12 @@ static int __init check_sdias(void)
 
        rc = sclp_sdias_blk_count();
        if (rc < 0) {
-               ERROR_MSG("Could not determine HSA size\n");
+               TRACE("Could not determine HSA size\n");
                return rc;
        }
        act_hsa_size = (rc - 1) * PAGE_SIZE;
        if (act_hsa_size < ZFCPDUMP_HSA_SIZE) {
-               ERROR_MSG("HSA size too small: %i\n", act_hsa_size);
+               TRACE("HSA size too small: %i\n", act_hsa_size);
                return -EINVAL;
        }
        return 0;
@@ -590,16 +589,12 @@ static int __init zcore_init(void)
                goto fail;
 
        rc = check_sdias();
-       if (rc) {
-               ERROR_MSG("Dump initialization failed\n");
+       if (rc)
                goto fail;
-       }
 
        rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
-       if (rc) {
-               ERROR_MSG("sdial memcpy for arch id failed\n");
+       if (rc)
                goto fail;
-       }
 
 #ifndef __s390x__
        if (arch == ARCH_S390X) {
@@ -610,10 +605,8 @@ static int __init zcore_init(void)
 #endif
 
        rc = sys_info_init(arch);
-       if (rc) {
-               ERROR_MSG("arch init failed\n");
+       if (rc)
                goto fail;
-       }
 
        zcore_header_init(arch, &zcore_header);
 
index cfaf77b320f5598d08d02067fe1ca79191eef0ab..91e9e3f3073af51b7ca4447a0143815dcc6fe9d8 100644 (file)
@@ -2,9 +2,11 @@
 # Makefile for the S/390 common i/o drivers
 #
 
-obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o
+obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
+       fcx.o itcw.o
 ccw_device-objs += device.o device_fsm.o device_ops.o
 ccw_device-objs += device_id.o device_pgid.o device_status.o
 obj-y += ccw_device.o cmf.o
+obj-$(CONFIG_CHSC_SCH) += chsc_sch.o
 obj-$(CONFIG_CCWGROUP) += ccwgroup.o
 obj-$(CONFIG_QDIO) += qdio.o
index b7a07a866291624a30a3ba13fab6bce3eb6034f7..fe6cea15bbaff371fd9daa9926438bf01480f881 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/rcupdate.h>
 
 #include <asm/airq.h>
+#include <asm/isc.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -33,15 +34,15 @@ struct airq_t {
        void *drv_data;
 };
 
-static union indicator_t indicators;
-static struct airq_t *airqs[NR_AIRQS];
+static union indicator_t indicators[MAX_ISC];
+static struct airq_t *airqs[MAX_ISC][NR_AIRQS];
 
-static int register_airq(struct airq_t *airq)
+static int register_airq(struct airq_t *airq, u8 isc)
 {
        int i;
 
        for (i = 0; i < NR_AIRQS; i++)
-               if (!cmpxchg(&airqs[i], NULL, airq))
+               if (!cmpxchg(&airqs[isc][i], NULL, airq))
                        return i;
        return -ENOMEM;
 }
@@ -50,18 +51,21 @@ static int register_airq(struct airq_t *airq)
  * s390_register_adapter_interrupt() - register adapter interrupt handler
  * @handler: adapter handler to be registered
  * @drv_data: driver data passed with each call to the handler
+ * @isc: isc for which the handler should be called
  *
  * Returns:
  *  Pointer to the indicator to be used on success
  *  ERR_PTR() if registration failed
  */
 void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
-                                     void *drv_data)
+                                     void *drv_data, u8 isc)
 {
        struct airq_t *airq;
        char dbf_txt[16];
        int ret;
 
+       if (isc > MAX_ISC)
+               return ERR_PTR(-EINVAL);
        airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
        if (!airq) {
                ret = -ENOMEM;
@@ -69,34 +73,35 @@ void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
        }
        airq->handler = handler;
        airq->drv_data = drv_data;
-       ret = register_airq(airq);
-       if (ret < 0)
-               kfree(airq);
+
+       ret = register_airq(airq, isc);
 out:
        snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
        CIO_TRACE_EVENT(4, dbf_txt);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(airq);
                return ERR_PTR(ret);
-       else
-               return &indicators.byte[ret];
+       else
+               return &indicators[isc].byte[ret];
 }
 EXPORT_SYMBOL(s390_register_adapter_interrupt);
 
 /**
  * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
  * @ind: indicator for which the handler is to be unregistered
+ * @isc: interruption subclass
  */
-void s390_unregister_adapter_interrupt(void *ind)
+void s390_unregister_adapter_interrupt(void *ind, u8 isc)
 {
        struct airq_t *airq;
        char dbf_txt[16];
        int i;
 
-       i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
+       i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]);
        snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
        CIO_TRACE_EVENT(4, dbf_txt);
-       indicators.byte[i] = 0;
-       airq = xchg(&airqs[i], NULL);
+       indicators[isc].byte[i] = 0;
+       airq = xchg(&airqs[isc][i], NULL);
        /*
         * Allow interrupts to complete. This will ensure that the airq handle
         * is no longer referenced by any interrupt handler.
@@ -108,7 +113,7 @@ EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
 
 #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
 
-void do_adapter_IO(void)
+void do_adapter_IO(u8 isc)
 {
        int w;
        int i;
@@ -120,22 +125,22 @@ void do_adapter_IO(void)
         * fetch operations.
         */
        for (w = 0; w < NR_AIRQ_WORDS; w++) {
-               word = indicators.word[w];
+               word = indicators[isc].word[w];
                i = w * NR_AIRQS_PER_WORD;
                /*
                 * Check bytes within word for active indicators.
                 */
                while (word) {
                        if (word & INDICATOR_MASK) {
-                               airq = airqs[i];
+                               airq = airqs[isc][i];
                                if (likely(airq))
-                                       airq->handler(&indicators.byte[i],
+                                       airq->handler(&indicators[isc].byte[i],
                                                      airq->drv_data);
                                else
                                        /*
                                         * Reset ill-behaved indicator.
                                         */
-                                       indicators.byte[i] = 0;
+                                       indicators[isc].byte[i] = 0;
                        }
                        word <<= 8;
                        i++;
index 297cdceb0ca4ba7276c57fbb8634bf6cb15f1eb9..db00b05917331b5901091f7697fa1fa2f2de8d96 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 
+#include "../s390mach.h"
 #include "cio.h"
 #include "css.h"
 #include "ioasm.h"
@@ -94,6 +95,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
        }
        return opm;
 }
+EXPORT_SYMBOL_GPL(chp_get_sch_opm);
 
 /**
  * chp_is_registered - check if a channel-path is registered
@@ -121,11 +123,8 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
        CIO_TRACE_EVENT(2, dbf_text);
 
        status = chp_get_status(chpid);
-       if (!on && !status) {
-               printk(KERN_ERR "cio: chpid %x.%02x is already offline\n",
-                      chpid.cssid, chpid.id);
-               return -EINVAL;
-       }
+       if (!on && !status)
+               return 0;
 
        set_chp_logically_online(chpid, on);
        chsc_chp_vary(chpid, on);
@@ -141,21 +140,14 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
 {
        struct channel_path *chp;
        struct device *device;
-       unsigned int size;
 
        device = container_of(kobj, struct device, kobj);
        chp = to_channelpath(device);
        if (!chp->cmg_chars)
                return 0;
 
-       size = sizeof(struct cmg_chars);
-
-       if (off > size)
-               return 0;
-       if (off + count > size)
-               count = size - off;
-       memcpy(buf, chp->cmg_chars + off, count);
-       return count;
+       return memory_read_from_buffer(buf, count, &off,
+                               chp->cmg_chars, sizeof(struct cmg_chars));
 }
 
 static struct bin_attribute chp_measurement_chars_attr = {
@@ -405,7 +397,7 @@ int chp_new(struct chp_id chpid)
                 chpid.id);
 
        /* Obtain channel path description and fill it in. */
-       ret = chsc_determine_channel_path_description(chpid, &chp->desc);
+       ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
        if (ret)
                goto out_free;
        if ((chp->desc.flags & 0x80) == 0) {
@@ -413,8 +405,7 @@ int chp_new(struct chp_id chpid)
                goto out_free;
        }
        /* Get channel-measurement characteristics. */
-       if (css_characteristics_avail && css_chsc_characteristics.scmc
-           && css_chsc_characteristics.secm) {
+       if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) {
                ret = chsc_get_channel_measurement_chars(chp);
                if (ret)
                        goto out_free;
@@ -476,26 +467,74 @@ void *chp_get_chp_desc(struct chp_id chpid)
 
 /**
  * chp_process_crw - process channel-path status change
- * @id: channel-path ID number
- * @status: non-zero if channel-path has become available, zero otherwise
+ * @crw0: channel report-word to handler
+ * @crw1: second channel-report word (always NULL)
+ * @overflow: crw overflow indication
  *
  * Handle channel-report-words indicating that the status of a channel-path
  * has changed.
  */
-void chp_process_crw(int id, int status)
+static void chp_process_crw(struct crw *crw0, struct crw *crw1,
+                           int overflow)
 {
        struct chp_id chpid;
 
+       if (overflow) {
+               css_schedule_eval_all();
+               return;
+       }
+       CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
+                     "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
+                     crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
+                     crw0->erc, crw0->rsid);
+       /*
+        * Check for solicited machine checks. These are
+        * created by reset channel path and need not be
+        * handled here.
+        */
+       if (crw0->slct) {
+               CIO_CRW_EVENT(2, "solicited machine check for "
+                             "channel path %02X\n", crw0->rsid);
+               return;
+       }
        chp_id_init(&chpid);
-       chpid.id = id;
-       if (status) {
+       chpid.id = crw0->rsid;
+       switch (crw0->erc) {
+       case CRW_ERC_IPARM: /* Path has come. */
                if (!chp_is_registered(chpid))
                        chp_new(chpid);
                chsc_chp_online(chpid);
-       } else
+               break;
+       case CRW_ERC_PERRI: /* Path has gone. */
+       case CRW_ERC_PERRN:
                chsc_chp_offline(chpid);
+               break;
+       default:
+               CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n",
+                             crw0->erc);
+       }
 }
 
+int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct chp_link *link)
+{
+       int i;
+       int mask;
+
+       for (i = 0; i < 8; i++) {
+               mask = 0x80 >> i;
+               if (!(ssd->path_mask & mask))
+                       continue;
+               if (!chp_id_is_equal(&ssd->chpid[i], &link->chpid))
+                       continue;
+               if ((ssd->fla_valid_mask & mask) &&
+                   ((ssd->fla[i] & link->fla_mask) != link->fla))
+                       continue;
+               return mask;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(chp_ssd_get_mask);
+
 static inline int info_bit_num(struct chp_id id)
 {
        return id.id + id.cssid * (__MAX_CHPID + 1);
@@ -575,6 +614,7 @@ static void cfg_func(struct work_struct *work)
 {
        struct chp_id chpid;
        enum cfg_task_t t;
+       int rc;
 
        mutex_lock(&cfg_lock);
        t = cfg_none;
@@ -589,14 +629,24 @@ static void cfg_func(struct work_struct *work)
 
        switch (t) {
        case cfg_configure:
-               sclp_chp_configure(chpid);
-               info_expire();
-               chsc_chp_online(chpid);
+               rc = sclp_chp_configure(chpid);
+               if (rc)
+                       CIO_MSG_EVENT(2, "chp: sclp_chp_configure(%x.%02x)="
+                                     "%d\n", chpid.cssid, chpid.id, rc);
+               else {
+                       info_expire();
+                       chsc_chp_online(chpid);
+               }
                break;
        case cfg_deconfigure:
-               sclp_chp_deconfigure(chpid);
-               info_expire();
-               chsc_chp_offline(chpid);
+               rc = sclp_chp_deconfigure(chpid);
+               if (rc)
+                       CIO_MSG_EVENT(2, "chp: sclp_chp_deconfigure(%x.%02x)="
+                                     "%d\n", chpid.cssid, chpid.id, rc);
+               else {
+                       info_expire();
+                       chsc_chp_offline(chpid);
+               }
                break;
        case cfg_none:
                /* Get updated information after last change. */
@@ -654,10 +704,16 @@ static int cfg_wait_idle(void)
 static int __init chp_init(void)
 {
        struct chp_id chpid;
+       int ret;
 
+       ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw);
+       if (ret)
+               return ret;
        chp_wq = create_singlethread_workqueue("cio_chp");
-       if (!chp_wq)
+       if (!chp_wq) {
+               s390_unregister_crw_handler(CRW_RSC_CPATH);
                return -ENOMEM;
+       }
        INIT_WORK(&cfg_work, cfg_func);
        init_waitqueue_head(&cfg_wait_queue);
        if (info_update())
index 65286563c592c70e47b1979c177910fc2c3f768c..26c3d22461764b56630958bbbfa6cb9714b166b0 100644 (file)
 #include <linux/device.h>
 #include <asm/chpid.h>
 #include "chsc.h"
+#include "css.h"
 
 #define CHP_STATUS_STANDBY             0
 #define CHP_STATUS_CONFIGURED          1
 #define CHP_STATUS_RESERVED            2
 #define CHP_STATUS_NOT_RECOGNIZED      3
 
+#define CHP_ONLINE 0
+#define CHP_OFFLINE 1
+#define CHP_VARY_ON 2
+#define CHP_VARY_OFF 3
+
+struct chp_link {
+       struct chp_id chpid;
+       u32 fla_mask;
+       u16 fla;
+};
+
 static inline int chp_test_bit(u8 *bitmap, int num)
 {
        int byte = num >> 3;
@@ -42,12 +54,11 @@ int chp_get_status(struct chp_id chpid);
 u8 chp_get_sch_opm(struct subchannel *sch);
 int chp_is_registered(struct chp_id chpid);
 void *chp_get_chp_desc(struct chp_id chpid);
-void chp_process_crw(int id, int available);
 void chp_remove_cmg_attr(struct channel_path *chp);
 int chp_add_cmg_attr(struct channel_path *chp);
 int chp_new(struct chp_id chpid);
 void chp_cfg_schedule(struct chp_id chpid, int configure);
 void chp_cfg_cancel_deconfigure(struct chp_id chpid);
 int chp_info_get_status(struct chp_id chpid);
-
+int chp_ssd_get_mask(struct chsc_ssd_info *, struct chp_link *);
 #endif /* S390_CHP_H */
index 5de86908b0d0c2f4f2a95425f09c07cfa6f160f1..65264a38057d5cba26ba13b80787800b030ee84e 100644 (file)
@@ -2,8 +2,7 @@
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
  *
- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
- *                           IBM Corporation
+ *    Copyright IBM Corp. 1999,2008
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
@@ -16,7 +15,9 @@
 
 #include <asm/cio.h>
 #include <asm/chpid.h>
+#include <asm/chsc.h>
 
+#include "../s390mach.h"
 #include "css.h"
 #include "cio.h"
 #include "cio_debug.h"
@@ -127,77 +128,12 @@ out_free:
        return ret;
 }
 
-static int check_for_io_on_path(struct subchannel *sch, int mask)
-{
-       int cc;
-
-       cc = stsch(sch->schid, &sch->schib);
-       if (cc)
-               return 0;
-       if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask)
-               return 1;
-       return 0;
-}
-
-static void terminate_internal_io(struct subchannel *sch)
-{
-       if (cio_clear(sch)) {
-               /* Recheck device in case clear failed. */
-               sch->lpm = 0;
-               if (device_trigger_verify(sch) != 0)
-                       css_schedule_eval(sch->schid);
-               return;
-       }
-       /* Request retry of internal operation. */
-       device_set_intretry(sch);
-       /* Call handler. */
-       if (sch->driver && sch->driver->termination)
-               sch->driver->termination(sch);
-}
-
 static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
 {
-       int j;
-       int mask;
-       struct chp_id *chpid = data;
-       struct schib schib;
-
-       for (j = 0; j < 8; j++) {
-               mask = 0x80 >> j;
-               if ((sch->schib.pmcw.pim & mask) &&
-                   (sch->schib.pmcw.chpid[j] == chpid->id))
-                       break;
-       }
-       if (j >= 8)
-               return 0;
-
        spin_lock_irq(sch->lock);
-
-       stsch(sch->schid, &schib);
-       if (!css_sch_is_valid(&schib))
-               goto out_unreg;
-       memcpy(&sch->schib, &schib, sizeof(struct schib));
-       /* Check for single path devices. */
-       if (sch->schib.pmcw.pim == 0x80)
-               goto out_unreg;
-
-       if (check_for_io_on_path(sch, mask)) {
-               if (device_is_online(sch))
-                       device_kill_io(sch);
-               else {
-                       terminate_internal_io(sch);
-                       /* Re-start path verification. */
-                       if (sch->driver && sch->driver->verify)
-                               sch->driver->verify(sch);
-               }
-       } else {
-               /* trigger path verification. */
-               if (sch->driver && sch->driver->verify)
-                       sch->driver->verify(sch);
-               else if (sch->lpm == mask)
+       if (sch->driver && sch->driver->chp_event)
+               if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0)
                        goto out_unreg;
-       }
-
        spin_unlock_irq(sch->lock);
        return 0;
 
@@ -211,15 +147,18 @@ out_unreg:
 void chsc_chp_offline(struct chp_id chpid)
 {
        char dbf_txt[15];
+       struct chp_link link;
 
        sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
        CIO_TRACE_EVENT(2, dbf_txt);
 
        if (chp_get_status(chpid) <= 0)
                return;
+       memset(&link, 0, sizeof(struct chp_link));
+       link.chpid = chpid;
        /* Wait until previous actions have settled. */
        css_wait_for_slow_path();
-       for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
+       for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);
 }
 
 static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
@@ -242,67 +181,25 @@ static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
        return 0;
 }
 
-struct res_acc_data {
-       struct chp_id chpid;
-       u32 fla_mask;
-       u16 fla;
-};
-
-static int get_res_chpid_mask(struct chsc_ssd_info *ssd,
-                             struct res_acc_data *data)
-{
-       int i;
-       int mask;
-
-       for (i = 0; i < 8; i++) {
-               mask = 0x80 >> i;
-               if (!(ssd->path_mask & mask))
-                       continue;
-               if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid))
-                       continue;
-               if ((ssd->fla_valid_mask & mask) &&
-                   ((ssd->fla[i] & data->fla_mask) != data->fla))
-                       continue;
-               return mask;
-       }
-       return 0;
-}
-
 static int __s390_process_res_acc(struct subchannel *sch, void *data)
 {
-       int chp_mask, old_lpm;
-       struct res_acc_data *res_data = data;
-
        spin_lock_irq(sch->lock);
-       chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
-       if (chp_mask == 0)
-               goto out;
-       if (stsch(sch->schid, &sch->schib))
-               goto out;
-       old_lpm = sch->lpm;
-       sch->lpm = ((sch->schib.pmcw.pim &
-                    sch->schib.pmcw.pam &
-                    sch->schib.pmcw.pom)
-                   | chp_mask) & sch->opm;
-       if (!old_lpm && sch->lpm)
-               device_trigger_reprobe(sch);
-       else if (sch->driver && sch->driver->verify)
-               sch->driver->verify(sch);
-out:
+       if (sch->driver && sch->driver->chp_event)
+               sch->driver->chp_event(sch, data, CHP_ONLINE);
        spin_unlock_irq(sch->lock);
 
        return 0;
 }
 
-static void s390_process_res_acc (struct res_acc_data *res_data)
+static void s390_process_res_acc(struct chp_link *link)
 {
        char dbf_txt[15];
 
-       sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid,
-               res_data->chpid.id);
+       sprintf(dbf_txt, "accpr%x.%02x", link->chpid.cssid,
+               link->chpid.id);
        CIO_TRACE_EVENT( 2, dbf_txt);
-       if (res_data->fla != 0) {
-               sprintf(dbf_txt, "fla%x", res_data->fla);
+       if (link->fla != 0) {
+               sprintf(dbf_txt, "fla%x", link->fla);
                CIO_TRACE_EVENT( 2, dbf_txt);
        }
        /* Wait until previous actions have settled. */
@@ -315,7 +212,7 @@ static void s390_process_res_acc (struct res_acc_data *res_data)
         * will we have to do.
         */
        for_each_subchannel_staged(__s390_process_res_acc,
-                                  s390_process_res_acc_new_sch, res_data);
+                                  s390_process_res_acc_new_sch, link);
 }
 
 static int
@@ -388,7 +285,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
 
 static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
 {
-       struct res_acc_data res_data;
+       struct chp_link link;
        struct chp_id chpid;
        int status;
 
@@ -404,18 +301,18 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
                chp_new(chpid);
        else if (!status)
                return;
-       memset(&res_data, 0, sizeof(struct res_acc_data));
-       res_data.chpid = chpid;
+       memset(&link, 0, sizeof(struct chp_link));
+       link.chpid = chpid;
        if ((sei_area->vf & 0xc0) != 0) {
-               res_data.fla = sei_area->fla;
+               link.fla = sei_area->fla;
                if ((sei_area->vf & 0xc0) == 0xc0)
                        /* full link address */
-                       res_data.fla_mask = 0xffff;
+                       link.fla_mask = 0xffff;
                else
                        /* link address */
-                       res_data.fla_mask = 0xff00;
+                       link.fla_mask = 0xff00;
        }
-       s390_process_res_acc(&res_data);
+       s390_process_res_acc(&link);
 }
 
 struct chp_config_data {
@@ -480,17 +377,25 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
        }
 }
 
-void chsc_process_crw(void)
+static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
 {
        struct chsc_sei_area *sei_area;
 
+       if (overflow) {
+               css_schedule_eval_all();
+               return;
+       }
+       CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
+                     "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
+                     crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
+                     crw0->erc, crw0->rsid);
        if (!sei_page)
                return;
        /* Access to sei_page is serialized through machine check handler
         * thread, so no need for locking. */
        sei_area = sei_page;
 
-       CIO_TRACE_EVENT( 2, "prcss");
+       CIO_TRACE_EVENT(2, "prcss");
        do {
                memset(sei_area, 0, sizeof(*sei_area));
                sei_area->request.length = 0x0010;
@@ -509,114 +414,36 @@ void chsc_process_crw(void)
        } while (sei_area->flags & 0x80);
 }
 
-static int __chp_add_new_sch(struct subchannel_id schid, void *data)
-{
-       struct schib schib;
-
-       if (stsch_err(schid, &schib))
-               /* We're through */
-               return -ENXIO;
-
-       /* Put it on the slow path. */
-       css_schedule_eval(schid);
-       return 0;
-}
-
-
-static int __chp_add(struct subchannel *sch, void *data)
-{
-       int i, mask;
-       struct chp_id *chpid = data;
-
-       spin_lock_irq(sch->lock);
-       for (i=0; i<8; i++) {
-               mask = 0x80 >> i;
-               if ((sch->schib.pmcw.pim & mask) &&
-                   (sch->schib.pmcw.chpid[i] == chpid->id))
-                       break;
-       }
-       if (i==8) {
-               spin_unlock_irq(sch->lock);
-               return 0;
-       }
-       if (stsch(sch->schid, &sch->schib)) {
-               spin_unlock_irq(sch->lock);
-               css_schedule_eval(sch->schid);
-               return 0;
-       }
-       sch->lpm = ((sch->schib.pmcw.pim &
-                    sch->schib.pmcw.pam &
-                    sch->schib.pmcw.pom)
-                   | mask) & sch->opm;
-
-       if (sch->driver && sch->driver->verify)
-               sch->driver->verify(sch);
-
-       spin_unlock_irq(sch->lock);
-
-       return 0;
-}
-
 void chsc_chp_online(struct chp_id chpid)
 {
        char dbf_txt[15];
+       struct chp_link link;
 
        sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
        CIO_TRACE_EVENT(2, dbf_txt);
 
        if (chp_get_status(chpid) != 0) {
+               memset(&link, 0, sizeof(struct chp_link));
+               link.chpid = chpid;
                /* Wait until previous actions have settled. */
                css_wait_for_slow_path();
-               for_each_subchannel_staged(__chp_add, __chp_add_new_sch,
-                                          &chpid);
+               for_each_subchannel_staged(__s390_process_res_acc, NULL,
+                                          &link);
        }
 }
 
 static void __s390_subchannel_vary_chpid(struct subchannel *sch,
                                         struct chp_id chpid, int on)
 {
-       int chp, old_lpm;
-       int mask;
        unsigned long flags;
+       struct chp_link link;
 
+       memset(&link, 0, sizeof(struct chp_link));
+       link.chpid = chpid;
        spin_lock_irqsave(sch->lock, flags);
-       old_lpm = sch->lpm;
-       for (chp = 0; chp < 8; chp++) {
-               mask = 0x80 >> chp;
-               if (!(sch->ssd_info.path_mask & mask))
-                       continue;
-               if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid))
-                       continue;
-
-               if (on) {
-                       sch->opm |= mask;
-                       sch->lpm |= mask;
-                       if (!old_lpm)
-                               device_trigger_reprobe(sch);
-                       else if (sch->driver && sch->driver->verify)
-                               sch->driver->verify(sch);
-                       break;
-               }
-               sch->opm &= ~mask;
-               sch->lpm &= ~mask;
-               if (check_for_io_on_path(sch, mask)) {
-                       if (device_is_online(sch))
-                               /* Path verification is done after killing. */
-                               device_kill_io(sch);
-                       else {
-                               /* Kill and retry internal I/O. */
-                               terminate_internal_io(sch);
-                               /* Re-start path verification. */
-                               if (sch->driver && sch->driver->verify)
-                                       sch->driver->verify(sch);
-                       }
-               } else if (!sch->lpm) {
-                       if (device_trigger_verify(sch) != 0)
-                               css_schedule_eval(sch->schid);
-               } else if (sch->driver && sch->driver->verify)
-                       sch->driver->verify(sch);
-               break;
-       }
+       if (sch->driver && sch->driver->chp_event)
+               sch->driver->chp_event(sch, &link,
+                                      on ? CHP_VARY_ON : CHP_VARY_OFF);
        spin_unlock_irqrestore(sch->lock, flags);
 }
 
@@ -656,6 +483,10 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data)
  */
 int chsc_chp_vary(struct chp_id chpid, int on)
 {
+       struct chp_link link;
+
+       memset(&link, 0, sizeof(struct chp_link));
+       link.chpid = chpid;
        /* Wait until previous actions have settled. */
        css_wait_for_slow_path();
        /*
@@ -664,10 +495,10 @@ int chsc_chp_vary(struct chp_id chpid, int on)
 
        if (on)
                for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
-                                          __s390_vary_chpid_on, &chpid);
+                                          __s390_vary_chpid_on, &link);
        else
                for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
-                                          NULL, &chpid);
+                                          NULL, &link);
 
        return 0;
 }
@@ -797,23 +628,33 @@ chsc_secm(struct channel_subsystem *css, int enable)
        return ret;
 }
 
-int chsc_determine_channel_path_description(struct chp_id chpid,
-                                           struct channel_path_desc *desc)
+int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
+                                    int c, int m,
+                                    struct chsc_response_struct *resp)
 {
        int ccode, ret;
 
        struct {
                struct chsc_header request;
-               u32 : 24;
+               u32 : 2;
+               u32 m : 1;
+               u32 c : 1;
+               u32 fmt : 4;
+               u32 cssid : 8;
+               u32 : 4;
+               u32 rfmt : 4;
                u32 first_chpid : 8;
                u32 : 24;
                u32 last_chpid : 8;
                u32 zeroes1;
                struct chsc_header response;
-               u32 zeroes2;
-               struct channel_path_desc desc;
+               u8 data[PAGE_SIZE - 20];
        } __attribute__ ((packed)) *scpd_area;
 
+       if ((rfmt == 1) && !css_general_characteristics.fcs)
+               return -EINVAL;
+       if ((rfmt == 2) && !css_general_characteristics.cib)
+               return -EINVAL;
        scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scpd_area)
                return -ENOMEM;
@@ -821,8 +662,13 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
        scpd_area->request.length = 0x0010;
        scpd_area->request.code = 0x0002;
 
+       scpd_area->cssid = chpid.cssid;
        scpd_area->first_chpid = chpid.id;
        scpd_area->last_chpid = chpid.id;
+       scpd_area->m = m;
+       scpd_area->c = c;
+       scpd_area->fmt = fmt;
+       scpd_area->rfmt = rfmt;
 
        ccode = chsc(scpd_area);
        if (ccode > 0) {
@@ -833,8 +679,7 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
        ret = chsc_error_from_response(scpd_area->response.code);
        if (ret == 0)
                /* Success. */
-               memcpy(desc, &scpd_area->desc,
-                      sizeof(struct channel_path_desc));
+               memcpy(resp, &scpd_area->response, scpd_area->response.length);
        else
                CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
                              scpd_area->response.code);
@@ -842,6 +687,25 @@ out:
        free_page((unsigned long)scpd_area);
        return ret;
 }
+EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc);
+
+int chsc_determine_base_channel_path_desc(struct chp_id chpid,
+                                         struct channel_path_desc *desc)
+{
+       struct chsc_response_struct *chsc_resp;
+       int ret;
+
+       chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL);
+       if (!chsc_resp)
+               return -ENOMEM;
+       ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp);
+       if (ret)
+               goto out_free;
+       memcpy(desc, &chsc_resp->data, chsc_resp->length);
+out_free:
+       kfree(chsc_resp);
+       return ret;
+}
 
 static void
 chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
@@ -937,15 +801,23 @@ out:
 
 int __init chsc_alloc_sei_area(void)
 {
+       int ret;
+
        sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!sei_page)
+       if (!sei_page) {
                CIO_MSG_EVENT(0, "Can't allocate page for processing of "
                              "chsc machine checks!\n");
-       return (sei_page ? 0 : -ENOMEM);
+               return -ENOMEM;
+       }
+       ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
+       if (ret)
+               kfree(sei_page);
+       return ret;
 }
 
 void __init chsc_free_sei_area(void)
 {
+       s390_unregister_crw_handler(CRW_RSC_CSS);
        kfree(sei_page);
 }
 
@@ -1043,3 +915,52 @@ exit:
 
 EXPORT_SYMBOL_GPL(css_general_characteristics);
 EXPORT_SYMBOL_GPL(css_chsc_characteristics);
+
+int chsc_sstpc(void *page, unsigned int op, u16 ctrl)
+{
+       struct {
+               struct chsc_header request;
+               unsigned int rsvd0;
+               unsigned int op : 8;
+               unsigned int rsvd1 : 8;
+               unsigned int ctrl : 16;
+               unsigned int rsvd2[5];
+               struct chsc_header response;
+               unsigned int rsvd3[7];
+       } __attribute__ ((packed)) *rr;
+       int rc;
+
+       memset(page, 0, PAGE_SIZE);
+       rr = page;
+       rr->request.length = 0x0020;
+       rr->request.code = 0x0033;
+       rr->op = op;
+       rr->ctrl = ctrl;
+       rc = chsc(rr);
+       if (rc)
+               return -EIO;
+       rc = (rr->response.code == 0x0001) ? 0 : -EIO;
+       return rc;
+}
+
+int chsc_sstpi(void *page, void *result, size_t size)
+{
+       struct {
+               struct chsc_header request;
+               unsigned int rsvd0[3];
+               struct chsc_header response;
+               char data[size];
+       } __attribute__ ((packed)) *rr;
+       int rc;
+
+       memset(page, 0, PAGE_SIZE);
+       rr = page;
+       rr->request.length = 0x0010;
+       rr->request.code = 0x0038;
+       rc = chsc(rr);
+       if (rc)
+               return -EIO;
+       memcpy(result, &rr->data, size);
+       return (rr->response.code == 0x0001) ? 0 : -EIO;
+}
+
index d1f5db1e69b94d6eee24aef06351fdb515abc1e4..fb6c4d6c45b44cc68f29b7bd7a8cd7372ef70d6e 100644 (file)
@@ -4,7 +4,8 @@
 #include <linux/types.h>
 #include <linux/device.h>
 #include <asm/chpid.h>
-#include "schid.h"
+#include <asm/chsc.h>
+#include <asm/schid.h>
 
 #define CHSC_SDA_OC_MSS   0x2
 
@@ -36,14 +37,15 @@ struct channel_path_desc {
 
 struct channel_path;
 
-extern void chsc_process_crw(void);
-
 struct css_general_char {
-       u64 : 41;
+       u64 : 12;
+       u32 dynio : 1;   /* bit 12 */
+       u32 : 28;
        u32 aif : 1;     /* bit 41 */
        u32 : 3;
        u32 mcss : 1;    /* bit 45 */
-       u32 : 2;
+       u32 fcs : 1;     /* bit 46 */
+       u32 : 1;
        u32 ext_mb : 1;  /* bit 48 */
        u32 : 7;
        u32 aif_tdd : 1; /* bit 56 */
@@ -51,7 +53,11 @@ struct css_general_char {
        u32 qebsm : 1;   /* bit 58 */
        u32 : 8;
        u32 aif_osa : 1; /* bit 67 */
-       u32 : 28;
+       u32 : 14;
+       u32 cib : 1;     /* bit 82 */
+       u32 : 5;
+       u32 fcx : 1;     /* bit 88 */
+       u32 : 7;
 }__attribute__((packed));
 
 struct css_chsc_char {
@@ -78,7 +84,6 @@ struct chsc_ssd_info {
 extern int chsc_get_ssd_info(struct subchannel_id schid,
                             struct chsc_ssd_info *ssd);
 extern int chsc_determine_css_characteristics(void);
-extern int css_characteristics_avail;
 extern int chsc_alloc_sei_area(void);
 extern void chsc_free_sei_area(void);
 
@@ -87,8 +92,11 @@ struct channel_subsystem;
 extern int chsc_secm(struct channel_subsystem *, int);
 
 int chsc_chp_vary(struct chp_id chpid, int on);
-int chsc_determine_channel_path_description(struct chp_id chpid,
-                                           struct channel_path_desc *desc);
+int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
+                                    int c, int m,
+                                    struct chsc_response_struct *resp);
+int chsc_determine_base_channel_path_desc(struct chp_id chpid,
+                                         struct channel_path_desc *desc);
 void chsc_chp_online(struct chp_id chpid);
 void chsc_chp_offline(struct chp_id chpid);
 int chsc_get_channel_measurement_chars(struct channel_path *chp);
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
new file mode 100644 (file)
index 0000000..91ca87a
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * Driver for s390 chsc subchannels
+ *
+ * Copyright IBM Corp. 2008
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+
+#include <asm/cio.h>
+#include <asm/chsc.h>
+#include <asm/isc.h>
+
+#include "cio.h"
+#include "cio_debug.h"
+#include "css.h"
+#include "chsc_sch.h"
+#include "ioasm.h"
+
+static debug_info_t *chsc_debug_msg_id;
+static debug_info_t *chsc_debug_log_id;
+
+#define CHSC_MSG(imp, args...) do {                                    \
+               debug_sprintf_event(chsc_debug_msg_id, imp , ##args);   \
+       } while (0)
+
+#define CHSC_LOG(imp, txt) do {                                        \
+               debug_text_event(chsc_debug_log_id, imp , txt); \
+       } while (0)
+
+static void CHSC_LOG_HEX(int level, void *data, int length)
+{
+       while (length > 0) {
+               debug_event(chsc_debug_log_id, level, data, length);
+               length -= chsc_debug_log_id->buf_size;
+               data += chsc_debug_log_id->buf_size;
+       }
+}
+
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("driver for s390 chsc subchannels");
+MODULE_LICENSE("GPL");
+
+static void chsc_subchannel_irq(struct subchannel *sch)
+{
+       struct chsc_private *private = sch->private;
+       struct chsc_request *request = private->request;
+       struct irb *irb = (struct irb *)__LC_IRB;
+
+       CHSC_LOG(4, "irb");
+       CHSC_LOG_HEX(4, irb, sizeof(*irb));
+       /* Copy irb to provided request and set done. */
+       if (!request) {
+               CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n",
+                        sch->schid.ssid, sch->schid.sch_no);
+               return;
+       }
+       private->request = NULL;
+       memcpy(&request->irb, irb, sizeof(*irb));
+       stsch(sch->schid, &sch->schib);
+       complete(&request->completion);
+       put_device(&sch->dev);
+}
+
+static int chsc_subchannel_probe(struct subchannel *sch)
+{
+       struct chsc_private *private;
+       int ret;
+
+       CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n",
+                sch->schid.ssid, sch->schid.sch_no);
+       sch->isc = CHSC_SCH_ISC;
+       private = kzalloc(sizeof(*private), GFP_KERNEL);
+       if (!private)
+               return -ENOMEM;
+       ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+       if (ret) {
+               CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n",
+                        sch->schid.ssid, sch->schid.sch_no, ret);
+               kfree(private);
+       } else {
+               sch->private = private;
+               if (sch->dev.uevent_suppress) {
+                       sch->dev.uevent_suppress = 0;
+                       kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+               }
+       }
+       return ret;
+}
+
+static int chsc_subchannel_remove(struct subchannel *sch)
+{
+       struct chsc_private *private;
+
+       cio_disable_subchannel(sch);
+       private = sch->private;
+       sch->private = NULL;
+       if (private->request) {
+               complete(&private->request->completion);
+               put_device(&sch->dev);
+       }
+       kfree(private);
+       return 0;
+}
+
+static void chsc_subchannel_shutdown(struct subchannel *sch)
+{
+       cio_disable_subchannel(sch);
+}
+
+static struct css_device_id chsc_subchannel_ids[] = {
+       { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(css, chsc_subchannel_ids);
+
+static struct css_driver chsc_subchannel_driver = {
+       .owner = THIS_MODULE,
+       .subchannel_type = chsc_subchannel_ids,
+       .irq = chsc_subchannel_irq,
+       .probe = chsc_subchannel_probe,
+       .remove = chsc_subchannel_remove,
+       .shutdown = chsc_subchannel_shutdown,
+       .name = "chsc_subchannel",
+};
+
+static int __init chsc_init_dbfs(void)
+{
+       chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
+                                          16 * sizeof(long));
+       if (!chsc_debug_msg_id)
+               goto out;
+       debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
+       debug_set_level(chsc_debug_msg_id, 2);
+       chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16);
+       if (!chsc_debug_log_id)
+               goto out;
+       debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view);
+       debug_set_level(chsc_debug_log_id, 2);
+       return 0;
+out:
+       if (chsc_debug_msg_id)
+               debug_unregister(chsc_debug_msg_id);
+       return -ENOMEM;
+}
+
+static void chsc_remove_dbfs(void)
+{
+       debug_unregister(chsc_debug_log_id);
+       debug_unregister(chsc_debug_msg_id);
+}
+
+static int __init chsc_init_sch_driver(void)
+{
+       return css_driver_register(&chsc_subchannel_driver);
+}
+
+static void chsc_cleanup_sch_driver(void)
+{
+       css_driver_unregister(&chsc_subchannel_driver);
+}
+
+static DEFINE_SPINLOCK(chsc_lock);
+
+static int chsc_subchannel_match_next_free(struct device *dev, void *data)
+{
+       struct subchannel *sch = to_subchannel(dev);
+
+       return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw);
+}
+
+static struct subchannel *chsc_get_next_subchannel(struct subchannel *sch)
+{
+       struct device *dev;
+
+       dev = driver_find_device(&chsc_subchannel_driver.drv,
+                                sch ? &sch->dev : NULL, NULL,
+                                chsc_subchannel_match_next_free);
+       return dev ? to_subchannel(dev) : NULL;
+}
+
+/**
+ * chsc_async() - try to start a chsc request asynchronously
+ * @chsc_area: request to be started
+ * @request: request structure to associate
+ *
+ * Tries to start a chsc request on one of the existing chsc subchannels.
+ * Returns:
+ *  %0 if the request was performed synchronously
+ *  %-EINPROGRESS if the request was successfully started
+ *  %-EBUSY if all chsc subchannels are busy
+ *  %-ENODEV if no chsc subchannels are available
+ * Context:
+ *  interrupts disabled, chsc_lock held
+ */
+static int chsc_async(struct chsc_async_area *chsc_area,
+                     struct chsc_request *request)
+{
+       int cc;
+       struct chsc_private *private;
+       struct subchannel *sch = NULL;
+       int ret = -ENODEV;
+       char dbf[10];
+
+       chsc_area->header.key = PAGE_DEFAULT_KEY;
+       while ((sch = chsc_get_next_subchannel(sch))) {
+               spin_lock(sch->lock);
+               private = sch->private;
+               if (private->request) {
+                       spin_unlock(sch->lock);
+                       ret = -EBUSY;
+                       continue;
+               }
+               chsc_area->header.sid = sch->schid;
+               CHSC_LOG(2, "schid");
+               CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid));
+               cc = chsc(chsc_area);
+               sprintf(dbf, "cc:%d", cc);
+               CHSC_LOG(2, dbf);
+               switch (cc) {
+               case 0:
+                       ret = 0;
+                       break;
+               case 1:
+                       sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC;
+                       ret = -EINPROGRESS;
+                       private->request = request;
+                       break;
+               case 2:
+                       ret = -EBUSY;
+                       break;
+               default:
+                       ret = -ENODEV;
+               }
+               spin_unlock(sch->lock);
+               CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n",
+                        sch->schid.ssid, sch->schid.sch_no, cc);
+               if (ret == -EINPROGRESS)
+                       return -EINPROGRESS;
+               put_device(&sch->dev);
+               if (ret == 0)
+                       return 0;
+       }
+       return ret;
+}
+
+static void chsc_log_command(struct chsc_async_area *chsc_area)
+{
+       char dbf[10];
+
+       sprintf(dbf, "CHSC:%x", chsc_area->header.code);
+       CHSC_LOG(0, dbf);
+       CHSC_LOG_HEX(0, chsc_area, 32);
+}
+
+static int chsc_examine_irb(struct chsc_request *request)
+{
+       int backed_up;
+
+       if (!scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND)
+               return -EIO;
+       backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK;
+       request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK;
+       if (scsw_cstat(&request->irb.scsw) == 0)
+               return 0;
+       if (!backed_up)
+               return 0;
+       if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK)
+               return -EIO;
+       if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK)
+               return -EPERM;
+       if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK)
+               return -EAGAIN;
+       if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK)
+               return -EAGAIN;
+       return -EIO;
+}
+
+static int chsc_ioctl_start(void __user *user_area)
+{
+       struct chsc_request *request;
+       struct chsc_async_area *chsc_area;
+       int ret;
+       char dbf[10];
+
+       if (!css_general_characteristics.dynio)
+               /* It makes no sense to try. */
+               return -EOPNOTSUPP;
+       chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
+       if (!chsc_area)
+               return -ENOMEM;
+       request = kzalloc(sizeof(*request), GFP_KERNEL);
+       if (!request) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       init_completion(&request->completion);
+       if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       chsc_log_command(chsc_area);
+       spin_lock_irq(&chsc_lock);
+       ret = chsc_async(chsc_area, request);
+       spin_unlock_irq(&chsc_lock);
+       if (ret == -EINPROGRESS) {
+               wait_for_completion(&request->completion);
+               ret = chsc_examine_irb(request);
+       }
+       /* copy area back to user */
+       if (!ret)
+               if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
+                       ret = -EFAULT;
+out_free:
+       sprintf(dbf, "ret:%d", ret);
+       CHSC_LOG(0, dbf);
+       kfree(request);
+       free_page((unsigned long)chsc_area);
+       return ret;
+}
+
+static int chsc_ioctl_info_channel_path(void __user *user_cd)
+{
+       struct chsc_chp_cd *cd;
+       int ret, ccode;
+       struct {
+               struct chsc_header request;
+               u32 : 2;
+               u32 m : 1;
+               u32 : 1;
+               u32 fmt1 : 4;
+               u32 cssid : 8;
+               u32 : 8;
+               u32 first_chpid : 8;
+               u32 : 24;
+               u32 last_chpid : 8;
+               u32 : 32;
+               struct chsc_header response;
+               u8 data[PAGE_SIZE - 20];
+       } __attribute__ ((packed)) *scpcd_area;
+
+       scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!scpcd_area)
+               return -ENOMEM;
+       cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+       if (!cd) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       if (copy_from_user(cd, user_cd, sizeof(*cd))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       scpcd_area->request.length = 0x0010;
+       scpcd_area->request.code = 0x0028;
+       scpcd_area->m = cd->m;
+       scpcd_area->fmt1 = cd->fmt;
+       scpcd_area->cssid = cd->chpid.cssid;
+       scpcd_area->first_chpid = cd->chpid.id;
+       scpcd_area->last_chpid = cd->chpid.id;
+
+       ccode = chsc(scpcd_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (scpcd_area->response.code != 0x0001) {
+               ret = -EIO;
+               CHSC_MSG(0, "scpcd: response code=%x\n",
+                        scpcd_area->response.code);
+               goto out_free;
+       }
+       memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length);
+       if (copy_to_user(user_cd, cd, sizeof(*cd)))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       kfree(cd);
+       free_page((unsigned long)scpcd_area);
+       return ret;
+}
+
+static int chsc_ioctl_info_cu(void __user *user_cd)
+{
+       struct chsc_cu_cd *cd;
+       int ret, ccode;
+       struct {
+               struct chsc_header request;
+               u32 : 2;
+               u32 m : 1;
+               u32 : 1;
+               u32 fmt1 : 4;
+               u32 cssid : 8;
+               u32 : 8;
+               u32 first_cun : 8;
+               u32 : 24;
+               u32 last_cun : 8;
+               u32 : 32;
+               struct chsc_header response;
+               u8 data[PAGE_SIZE - 20];
+       } __attribute__ ((packed)) *scucd_area;
+
+       scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!scucd_area)
+               return -ENOMEM;
+       cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+       if (!cd) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       if (copy_from_user(cd, user_cd, sizeof(*cd))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       scucd_area->request.length = 0x0010;
+       scucd_area->request.code = 0x0028;
+       scucd_area->m = cd->m;
+       scucd_area->fmt1 = cd->fmt;
+       scucd_area->cssid = cd->cssid;
+       scucd_area->first_cun = cd->cun;
+       scucd_area->last_cun = cd->cun;
+
+       ccode = chsc(scucd_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (scucd_area->response.code != 0x0001) {
+               ret = -EIO;
+               CHSC_MSG(0, "scucd: response code=%x\n",
+                        scucd_area->response.code);
+               goto out_free;
+       }
+       memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length);
+       if (copy_to_user(user_cd, cd, sizeof(*cd)))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       kfree(cd);
+       free_page((unsigned long)scucd_area);
+       return ret;
+}
+
+static int chsc_ioctl_info_sch_cu(void __user *user_cud)
+{
+       struct chsc_sch_cud *cud;
+       int ret, ccode;
+       struct {
+               struct chsc_header request;
+               u32 : 2;
+               u32 m : 1;
+               u32 : 5;
+               u32 fmt1 : 4;
+               u32 : 2;
+               u32 ssid : 2;
+               u32 first_sch : 16;
+               u32 : 8;
+               u32 cssid : 8;
+               u32 last_sch : 16;
+               u32 : 32;
+               struct chsc_header response;
+               u8 data[PAGE_SIZE - 20];
+       } __attribute__ ((packed)) *sscud_area;
+
+       sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sscud_area)
+               return -ENOMEM;
+       cud = kzalloc(sizeof(*cud), GFP_KERNEL);
+       if (!cud) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       if (copy_from_user(cud, user_cud, sizeof(*cud))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       sscud_area->request.length = 0x0010;
+       sscud_area->request.code = 0x0006;
+       sscud_area->m = cud->schid.m;
+       sscud_area->fmt1 = cud->fmt;
+       sscud_area->ssid = cud->schid.ssid;
+       sscud_area->first_sch = cud->schid.sch_no;
+       sscud_area->cssid = cud->schid.cssid;
+       sscud_area->last_sch = cud->schid.sch_no;
+
+       ccode = chsc(sscud_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (sscud_area->response.code != 0x0001) {
+               ret = -EIO;
+               CHSC_MSG(0, "sscud: response code=%x\n",
+                        sscud_area->response.code);
+               goto out_free;
+       }
+       memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length);
+       if (copy_to_user(user_cud, cud, sizeof(*cud)))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       kfree(cud);
+       free_page((unsigned long)sscud_area);
+       return ret;
+}
+
+static int chsc_ioctl_conf_info(void __user *user_ci)
+{
+       struct chsc_conf_info *ci;
+       int ret, ccode;
+       struct {
+               struct chsc_header request;
+               u32 : 2;
+               u32 m : 1;
+               u32 : 1;
+               u32 fmt1 : 4;
+               u32 cssid : 8;
+               u32 : 6;
+               u32 ssid : 2;
+               u32 : 8;
+               u64 : 64;
+               struct chsc_header response;
+               u8 data[PAGE_SIZE - 20];
+       } __attribute__ ((packed)) *sci_area;
+
+       sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sci_area)
+               return -ENOMEM;
+       ci = kzalloc(sizeof(*ci), GFP_KERNEL);
+       if (!ci) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       if (copy_from_user(ci, user_ci, sizeof(*ci))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       sci_area->request.length = 0x0010;
+       sci_area->request.code = 0x0012;
+       sci_area->m = ci->id.m;
+       sci_area->fmt1 = ci->fmt;
+       sci_area->cssid = ci->id.cssid;
+       sci_area->ssid = ci->id.ssid;
+
+       ccode = chsc(sci_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (sci_area->response.code != 0x0001) {
+               ret = -EIO;
+               CHSC_MSG(0, "sci: response code=%x\n",
+                        sci_area->response.code);
+               goto out_free;
+       }
+       memcpy(&ci->scid, &sci_area->response, sci_area->response.length);
+       if (copy_to_user(user_ci, ci, sizeof(*ci)))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       kfree(ci);
+       free_page((unsigned long)sci_area);
+       return ret;
+}
+
+static int chsc_ioctl_conf_comp_list(void __user *user_ccl)
+{
+       struct chsc_comp_list *ccl;
+       int ret, ccode;
+       struct {
+               struct chsc_header request;
+               u32 ctype : 8;
+               u32 : 4;
+               u32 fmt : 4;
+               u32 : 16;
+               u64 : 64;
+               u32 list_parm[2];
+               u64 : 64;
+               struct chsc_header response;
+               u8 data[PAGE_SIZE - 36];
+       } __attribute__ ((packed)) *sccl_area;
+       struct {
+               u32 m : 1;
+               u32 : 31;
+               u32 cssid : 8;
+               u32 : 16;
+               u32 chpid : 8;
+       } __attribute__ ((packed)) *chpid_parm;
+       struct {
+               u32 f_cssid : 8;
+               u32 l_cssid : 8;
+               u32 : 16;
+               u32 res;
+       } __attribute__ ((packed)) *cssids_parm;
+
+       sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccl_area)
+               return -ENOMEM;
+       ccl = kzalloc(sizeof(*ccl), GFP_KERNEL);
+       if (!ccl) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       sccl_area->request.length = 0x0020;
+       sccl_area->request.code = 0x0030;
+       sccl_area->fmt = ccl->req.fmt;
+       sccl_area->ctype = ccl->req.ctype;
+       switch (sccl_area->ctype) {
+       case CCL_CU_ON_CHP:
+       case CCL_IOP_CHP:
+               chpid_parm = (void *)&sccl_area->list_parm;
+               chpid_parm->m = ccl->req.chpid.m;
+               chpid_parm->cssid = ccl->req.chpid.chp.cssid;
+               chpid_parm->chpid = ccl->req.chpid.chp.id;
+               break;
+       case CCL_CSS_IMG:
+       case CCL_CSS_IMG_CONF_CHAR:
+               cssids_parm = (void *)&sccl_area->list_parm;
+               cssids_parm->f_cssid = ccl->req.cssids.f_cssid;
+               cssids_parm->l_cssid = ccl->req.cssids.l_cssid;
+               break;
+       }
+       ccode = chsc(sccl_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (sccl_area->response.code != 0x0001) {
+               ret = -EIO;
+               CHSC_MSG(0, "sccl: response code=%x\n",
+                        sccl_area->response.code);
+               goto out_free;
+       }
+       memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length);
+       if (copy_to_user(user_ccl, ccl, sizeof(*ccl)))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       kfree(ccl);
+       free_page((unsigned long)sccl_area);
+       return ret;
+}
+
+static int chsc_ioctl_chpd(void __user *user_chpd)
+{
+       struct chsc_cpd_info *chpd;
+       int ret;
+
+       chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
+       if (!chpd)
+               return -ENOMEM;
+       if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt,
+                                              chpd->rfmt, chpd->c, chpd->m,
+                                              &chpd->chpdb);
+       if (ret)
+               goto out_free;
+       if (copy_to_user(user_chpd, chpd, sizeof(*chpd)))
+               ret = -EFAULT;
+out_free:
+       kfree(chpd);
+       return ret;
+}
+
+static int chsc_ioctl_dcal(void __user *user_dcal)
+{
+       struct chsc_dcal *dcal;
+       int ret, ccode;
+       struct {
+               struct chsc_header request;
+               u32 atype : 8;
+               u32 : 4;
+               u32 fmt : 4;
+               u32 : 16;
+               u32 res0[2];
+               u32 list_parm[2];
+               u32 res1[2];
+               struct chsc_header response;
+               u8 data[PAGE_SIZE - 36];
+       } __attribute__ ((packed)) *sdcal_area;
+
+       sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sdcal_area)
+               return -ENOMEM;
+       dcal = kzalloc(sizeof(*dcal), GFP_KERNEL);
+       if (!dcal) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       sdcal_area->request.length = 0x0020;
+       sdcal_area->request.code = 0x0034;
+       sdcal_area->atype = dcal->req.atype;
+       sdcal_area->fmt = dcal->req.fmt;
+       memcpy(&sdcal_area->list_parm, &dcal->req.list_parm,
+              sizeof(sdcal_area->list_parm));
+
+       ccode = chsc(sdcal_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (sdcal_area->response.code != 0x0001) {
+               ret = -EIO;
+               CHSC_MSG(0, "sdcal: response code=%x\n",
+                        sdcal_area->response.code);
+               goto out_free;
+       }
+       memcpy(&dcal->sdcal, &sdcal_area->response,
+              sdcal_area->response.length);
+       if (copy_to_user(user_dcal, dcal, sizeof(*dcal)))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       kfree(dcal);
+       free_page((unsigned long)sdcal_area);
+       return ret;
+}
+
+static long chsc_ioctl(struct file *filp, unsigned int cmd,
+                      unsigned long arg)
+{
+       CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd);
+       switch (cmd) {
+       case CHSC_START:
+               return chsc_ioctl_start((void __user *)arg);
+       case CHSC_INFO_CHANNEL_PATH:
+               return chsc_ioctl_info_channel_path((void __user *)arg);
+       case CHSC_INFO_CU:
+               return chsc_ioctl_info_cu((void __user *)arg);
+       case CHSC_INFO_SCH_CU:
+               return chsc_ioctl_info_sch_cu((void __user *)arg);
+       case CHSC_INFO_CI:
+               return chsc_ioctl_conf_info((void __user *)arg);
+       case CHSC_INFO_CCL:
+               return chsc_ioctl_conf_comp_list((void __user *)arg);
+       case CHSC_INFO_CPD:
+               return chsc_ioctl_chpd((void __user *)arg);
+       case CHSC_INFO_DCAL:
+               return chsc_ioctl_dcal((void __user *)arg);
+       default: /* unknown ioctl number */
+               return -ENOIOCTLCMD;
+       }
+}
+
+static const struct file_operations chsc_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = chsc_ioctl,
+       .compat_ioctl = chsc_ioctl,
+};
+
+static struct miscdevice chsc_misc_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "chsc",
+       .fops = &chsc_fops,
+};
+
+static int __init chsc_misc_init(void)
+{
+       return misc_register(&chsc_misc_device);
+}
+
+static void chsc_misc_cleanup(void)
+{
+       misc_deregister(&chsc_misc_device);
+}
+
+static int __init chsc_sch_init(void)
+{
+       int ret;
+
+       ret = chsc_init_dbfs();
+       if (ret)
+               return ret;
+       isc_register(CHSC_SCH_ISC);
+       ret = chsc_init_sch_driver();
+       if (ret)
+               goto out_dbf;
+       ret = chsc_misc_init();
+       if (ret)
+               goto out_driver;
+       return ret;
+out_driver:
+       chsc_cleanup_sch_driver();
+out_dbf:
+       isc_unregister(CHSC_SCH_ISC);
+       chsc_remove_dbfs();
+       return ret;
+}
+
+static void __exit chsc_sch_exit(void)
+{
+       chsc_misc_cleanup();
+       chsc_cleanup_sch_driver();
+       isc_unregister(CHSC_SCH_ISC);
+       chsc_remove_dbfs();
+}
+
+module_init(chsc_sch_init);
+module_exit(chsc_sch_exit);
diff --git a/drivers/s390/cio/chsc_sch.h b/drivers/s390/cio/chsc_sch.h
new file mode 100644 (file)
index 0000000..589ebfa
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _CHSC_SCH_H
+#define _CHSC_SCH_H
+
+struct chsc_request {
+       struct completion completion;
+       struct irb irb;
+};
+
+struct chsc_private {
+       struct chsc_request *request;
+};
+
+#endif
index b32d7eb3d81a4d8ee3dc29fb587bc78f91b5b7e8..33bff8fec7d10b0a5b02cb0ed0824cdd210b2256 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
  *
- *    Copyright (C) IBM Corp. 1999,2006
+ *    Copyright IBM Corp. 1999,2008
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
@@ -24,7 +24,9 @@
 #include <asm/ipl.h>
 #include <asm/chpid.h>
 #include <asm/airq.h>
+#include <asm/isc.h>
 #include <asm/cpu.h>
+#include <asm/fcx.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
@@ -72,7 +74,6 @@ out_unregister:
                debug_unregister(cio_debug_trace_id);
        if (cio_debug_crw_id)
                debug_unregister(cio_debug_crw_id);
-       printk(KERN_WARNING"cio: could not initialize debugging\n");
        return -1;
 }
 
@@ -128,7 +129,7 @@ cio_tpi(void)
        local_bh_disable();
        irq_enter ();
        spin_lock(sch->lock);
-       memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
+       memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
        if (sch->driver && sch->driver->irq)
                sch->driver->irq(sch);
        spin_unlock(sch->lock);
@@ -167,30 +168,30 @@ cio_start_key (struct subchannel *sch,    /* subchannel structure */
 {
        char dbf_txt[15];
        int ccode;
-       struct orb *orb;
+       union orb *orb;
 
        CIO_TRACE_EVENT(4, "stIO");
        CIO_TRACE_EVENT(4, sch->dev.bus_id);
 
        orb = &to_io_private(sch)->orb;
        /* sch is always under 2G. */
-       orb->intparm = (u32)(addr_t)sch;
-       orb->fmt = 1;
+       orb->cmd.intparm = (u32)(addr_t)sch;
+       orb->cmd.fmt = 1;
 
-       orb->pfch = sch->options.prefetch == 0;
-       orb->spnd = sch->options.suspend;
-       orb->ssic = sch->options.suspend && sch->options.inter;
-       orb->lpm = (lpm != 0) ? lpm : sch->lpm;
+       orb->cmd.pfch = sch->options.prefetch == 0;
+       orb->cmd.spnd = sch->options.suspend;
+       orb->cmd.ssic = sch->options.suspend && sch->options.inter;
+       orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
 #ifdef CONFIG_64BIT
        /*
         * for 64 bit we always support 64 bit IDAWs with 4k page size only
         */
-       orb->c64 = 1;
-       orb->i2k = 0;
+       orb->cmd.c64 = 1;
+       orb->cmd.i2k = 0;
 #endif
-       orb->key = key >> 4;
+       orb->cmd.key = key >> 4;
        /* issue "Start Subchannel" */
-       orb->cpa = (__u32) __pa(cpa);
+       orb->cmd.cpa = (__u32) __pa(cpa);
        ccode = ssch(sch->schid, orb);
 
        /* process condition code */
@@ -202,7 +203,7 @@ cio_start_key (struct subchannel *sch,      /* subchannel structure */
                /*
                 * initialize device status information
                 */
-               sch->schib.scsw.actl |= SCSW_ACTL_START_PEND;
+               sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
                return 0;
        case 1:         /* status pending */
        case 2:         /* busy */
@@ -237,7 +238,7 @@ cio_resume (struct subchannel *sch)
 
        switch (ccode) {
        case 0:
-               sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND;
+               sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND;
                return 0;
        case 1:
                return -EBUSY;
@@ -277,7 +278,7 @@ cio_halt(struct subchannel *sch)
 
        switch (ccode) {
        case 0:
-               sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND;
+               sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
                return 0;
        case 1:         /* status pending */
        case 2:         /* busy */
@@ -312,7 +313,7 @@ cio_clear(struct subchannel *sch)
 
        switch (ccode) {
        case 0:
-               sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND;
+               sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND;
                return 0;
        default:                /* device not operational */
                return -ENODEV;
@@ -387,8 +388,10 @@ cio_modify (struct subchannel *sch)
        return ret;
 }
 
-/*
- * Enable subchannel.
+/**
+ * cio_enable_subchannel - enable a subchannel.
+ * @sch: subchannel to be enabled
+ * @intparm: interruption parameter to set
  */
 int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
 {
@@ -434,12 +437,13 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
        CIO_TRACE_EVENT (2, dbf_txt);
        return ret;
 }
+EXPORT_SYMBOL_GPL(cio_enable_subchannel);
 
-/*
- * Disable subchannel.
+/**
+ * cio_disable_subchannel - disable a subchannel.
+ * @sch: subchannel to disable
  */
-int
-cio_disable_subchannel (struct subchannel *sch)
+int cio_disable_subchannel(struct subchannel *sch)
 {
        char dbf_txt[15];
        int ccode;
@@ -455,7 +459,7 @@ cio_disable_subchannel (struct subchannel *sch)
        if (ccode == 3)         /* Not operational. */
                return -ENODEV;
 
-       if (sch->schib.scsw.actl != 0)
+       if (scsw_actl(&sch->schib.scsw) != 0)
                /*
                 * the disable function must not be called while there are
                 *  requests pending for completion !
@@ -484,6 +488,7 @@ cio_disable_subchannel (struct subchannel *sch)
        CIO_TRACE_EVENT (2, dbf_txt);
        return ret;
 }
+EXPORT_SYMBOL_GPL(cio_disable_subchannel);
 
 int cio_create_sch_lock(struct subchannel *sch)
 {
@@ -494,27 +499,61 @@ int cio_create_sch_lock(struct subchannel *sch)
        return 0;
 }
 
-/*
- * cio_validate_subchannel()
+static int cio_check_devno_blacklisted(struct subchannel *sch)
+{
+       if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
+               /*
+                * This device must not be known to Linux. So we simply
+                * say that there is no device and return ENODEV.
+                */
+               CIO_MSG_EVENT(6, "Blacklisted device detected "
+                             "at devno %04X, subchannel set %x\n",
+                             sch->schib.pmcw.dev, sch->schid.ssid);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int cio_validate_io_subchannel(struct subchannel *sch)
+{
+       /* Initialization for io subchannels. */
+       if (!css_sch_is_valid(&sch->schib))
+               return -ENODEV;
+
+       /* Devno is valid. */
+       return cio_check_devno_blacklisted(sch);
+}
+
+static int cio_validate_msg_subchannel(struct subchannel *sch)
+{
+       /* Initialization for message subchannels. */
+       if (!css_sch_is_valid(&sch->schib))
+               return -ENODEV;
+
+       /* Devno is valid. */
+       return cio_check_devno_blacklisted(sch);
+}
+
+/**
+ * cio_validate_subchannel - basic validation of subchannel
+ * @sch: subchannel structure to be filled out
+ * @schid: subchannel id
  *
  * Find out subchannel type and initialize struct subchannel.
  * Return codes:
- *   SUBCHANNEL_TYPE_IO for a normal io subchannel
- *   SUBCHANNEL_TYPE_CHSC for a chsc subchannel
- *   SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel
- *   SUBCHANNEL_TYPE_ADM for a adm(?) subchannel
+ *   0 on success
  *   -ENXIO for non-defined subchannels
- *   -ENODEV for subchannels with invalid device number or blacklisted devices
+ *   -ENODEV for invalid subchannels or blacklisted devices
+ *   -EIO for subchannels in an invalid subchannel set
  */
-int
-cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
+int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
 {
        char dbf_txt[15];
        int ccode;
        int err;
 
-       sprintf (dbf_txt, "valsch%x", schid.sch_no);
-       CIO_TRACE_EVENT (4, dbf_txt);
+       sprintf(dbf_txt, "valsch%x", schid.sch_no);
+       CIO_TRACE_EVENT(4, dbf_txt);
 
        /* Nuke all fields. */
        memset(sch, 0, sizeof(struct subchannel));
@@ -546,67 +585,21 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        /* Copy subchannel type from path management control word. */
        sch->st = sch->schib.pmcw.st;
 
-       /*
-        * ... just being curious we check for non I/O subchannels
-        */
-       if (sch->st != 0) {
-               CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports "
-                             "non-I/O subchannel type %04X\n",
-                             sch->schid.ssid, sch->schid.sch_no, sch->st);
-               /* We stop here for non-io subchannels. */
-               err = sch->st;
-               goto out;
-       }
-
-       /* Initialization for io subchannels. */
-       if (!css_sch_is_valid(&sch->schib)) {
-               err = -ENODEV;
-               goto out;
+       switch (sch->st) {
+       case SUBCHANNEL_TYPE_IO:
+               err = cio_validate_io_subchannel(sch);
+               break;
+       case SUBCHANNEL_TYPE_MSG:
+               err = cio_validate_msg_subchannel(sch);
+               break;
+       default:
+               err = 0;
        }
-
-       /* Devno is valid. */
-       if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
-               /*
-                * This device must not be known to Linux. So we simply
-                * say that there is no device and return ENODEV.
-                */
-               CIO_MSG_EVENT(6, "Blacklisted device detected "
-                             "at devno %04X, subchannel set %x\n",
-                             sch->schib.pmcw.dev, sch->schid.ssid);
-               err = -ENODEV;
+       if (err)
                goto out;
-       }
-       if (cio_is_console(sch->schid)) {
-               sch->opm = 0xff;
-               sch->isc = 1;
-       } else {
-               sch->opm = chp_get_sch_opm(sch);
-               sch->isc = 3;
-       }
-       sch->lpm = sch->schib.pmcw.pam & sch->opm;
-
-       CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X "
-                     "- PIM = %02X, PAM = %02X, POM = %02X\n",
-                     sch->schib.pmcw.dev, sch->schid.ssid,
-                     sch->schid.sch_no, sch->schib.pmcw.pim,
-                     sch->schib.pmcw.pam, sch->schib.pmcw.pom);
 
-       /*
-        * We now have to initially ...
-        *  ... enable "concurrent sense"
-        *  ... enable "multipath mode" if more than one
-        *        CHPID is available. This is done regardless
-        *        whether multiple paths are available for us.
-        */
-       sch->schib.pmcw.csense = 1;     /* concurrent sense */
-       sch->schib.pmcw.ena = 0;
-       if ((sch->lpm & (sch->lpm - 1)) != 0)
-               sch->schib.pmcw.mp = 1; /* multipath mode */
-       /* clean up possible residual cmf stuff */
-       sch->schib.pmcw.mme = 0;
-       sch->schib.pmcw.mbfc = 0;
-       sch->schib.pmcw.mbi = 0;
-       sch->schib.mba = 0;
+       CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
+                     sch->schid.ssid, sch->schid.sch_no, sch->st);
        return 0;
 out:
        if (!cio_is_console(schid))
@@ -647,7 +640,7 @@ do_IRQ (struct pt_regs *regs)
                 */
                if (tpi_info->adapter_IO == 1 &&
                    tpi_info->int_type == IO_INTERRUPT_TYPE) {
-                       do_adapter_IO();
+                       do_adapter_IO(tpi_info->isc);
                        continue;
                }
                sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
@@ -706,9 +699,9 @@ void wait_cons_dev(void)
        if (!console_subchannel_in_use)
                return;
 
-       /* disable all but isc 1 (console device) */
+       /* disable all but the console isc */
        __ctl_store (save_cr6, 6, 6);
-       cr6 = 0x40000000;
+       cr6 = 1UL << (31 - CONSOLE_ISC);
        __ctl_load (cr6, 6, 6);
 
        do {
@@ -716,7 +709,7 @@ void wait_cons_dev(void)
                if (!cio_tpi())
                        cpu_relax();
                spin_lock(console_subchannel.lock);
-       } while (console_subchannel.schib.scsw.actl != 0);
+       } while (console_subchannel.schib.scsw.cmd.actl != 0);
        /*
         * restore previous isc value
         */
@@ -761,7 +754,6 @@ cio_get_console_sch_no(void)
                /* unlike in 2.4, we cannot autoprobe here, since
                 * the channel subsystem is not fully initialized.
                 * With some luck, the HWC console can take over */
-               printk(KERN_WARNING "cio: No ccw console found!\n");
                return -1;
        }
        return console_irq;
@@ -778,6 +770,7 @@ cio_probe_console(void)
        sch_no = cio_get_console_sch_no();
        if (sch_no == -1) {
                console_subchannel_in_use = 0;
+               printk(KERN_WARNING "cio: No ccw console found!\n");
                return ERR_PTR(-ENODEV);
        }
        memset(&console_subchannel, 0, sizeof(struct subchannel));
@@ -790,15 +783,15 @@ cio_probe_console(void)
        }
 
        /*
-        * enable console I/O-interrupt subclass 1
+        * enable console I/O-interrupt subclass
         */
-       ctl_set_bit(6, 30);
-       console_subchannel.isc = 1;
-       console_subchannel.schib.pmcw.isc = 1;
+       isc_register(CONSOLE_ISC);
+       console_subchannel.schib.pmcw.isc = CONSOLE_ISC;
        console_subchannel.schib.pmcw.intparm =
                (u32)(addr_t)&console_subchannel;
        ret = cio_modify(&console_subchannel);
        if (ret) {
+               isc_unregister(CONSOLE_ISC);
                console_subchannel_in_use = 0;
                return ERR_PTR(ret);
        }
@@ -810,7 +803,7 @@ cio_release_console(void)
 {
        console_subchannel.schib.pmcw.intparm = 0;
        cio_modify(&console_subchannel);
-       ctl_clear_bit(6, 24);
+       isc_unregister(CONSOLE_ISC);
        console_subchannel_in_use = 0;
 }
 
@@ -864,7 +857,7 @@ static void udelay_reset(unsigned long usecs)
 }
 
 static int
-__clear_subchannel_easy(struct subchannel_id schid)
+__clear_io_subchannel_easy(struct subchannel_id schid)
 {
        int retry;
 
@@ -883,6 +876,12 @@ __clear_subchannel_easy(struct subchannel_id schid)
        return -EBUSY;
 }
 
+static void __clear_chsc_subchannel_easy(void)
+{
+       /* It seems we can only wait for a bit here :/ */
+       udelay_reset(100);
+}
+
 static int pgm_check_occured;
 
 static void cio_reset_pgm_check_handler(void)
@@ -921,11 +920,22 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
        case -ENODEV:
                break;
        default: /* -EBUSY */
-               if (__clear_subchannel_easy(schid))
-                       break; /* give up... */
+               switch (schib.pmcw.st) {
+               case SUBCHANNEL_TYPE_IO:
+                       if (__clear_io_subchannel_easy(schid))
+                               goto out; /* give up... */
+                       break;
+               case SUBCHANNEL_TYPE_CHSC:
+                       __clear_chsc_subchannel_easy();
+                       break;
+               default:
+                       /* No default clear strategy */
+                       break;
+               }
                stsch(schid, &schib);
                __disable_subchannel_easy(schid, &schib);
        }
+out:
        return 0;
 }
 
@@ -1068,3 +1078,61 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
        iplinfo->is_qdio = schib.pmcw.qf;
        return 0;
 }
+
+/**
+ * cio_tm_start_key - perform start function
+ * @sch: subchannel on which to perform the start function
+ * @tcw: transport-command word to be started
+ * @lpm: mask of paths to use
+ * @key: storage key to use for storage access
+ *
+ * Start the tcw on the given subchannel. Return zero on success, non-zero
+ * otherwise.
+ */
+int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
+{
+       int cc;
+       union orb *orb = &to_io_private(sch)->orb;
+
+       memset(orb, 0, sizeof(union orb));
+       orb->tm.intparm = (u32) (addr_t) sch;
+       orb->tm.key = key >> 4;
+       orb->tm.b = 1;
+       orb->tm.lpm = lpm ? lpm : sch->lpm;
+       orb->tm.tcw = (u32) (addr_t) tcw;
+       cc = ssch(sch->schid, orb);
+       switch (cc) {
+       case 0:
+               return 0;
+       case 1:
+       case 2:
+               return -EBUSY;
+       default:
+               return cio_start_handle_notoper(sch, lpm);
+       }
+}
+
+/**
+ * cio_tm_intrg - perform interrogate function
+ * @sch - subchannel on which to perform the interrogate function
+ *
+ * If the specified subchannel is running in transport-mode, perform the
+ * interrogate function. Return zero on success, non-zero otherwie.
+ */
+int cio_tm_intrg(struct subchannel *sch)
+{
+       int cc;
+
+       if (!to_io_private(sch)->orb.tm.b)
+               return -EINVAL;
+       cc = xsch(sch->schid);
+       switch (cc) {
+       case 0:
+       case 2:
+               return 0;
+       case 1:
+               return -EBUSY;
+       default:
+               return -ENODEV;
+       }
+}
index 6e933aebe01308e2882f45f0320c72a9612e133d..3b236d20e83543ec127a279d132ec7f51df63958 100644 (file)
@@ -3,9 +3,12 @@
 
 #include <linux/mutex.h>
 #include <linux/device.h>
+#include <linux/mod_devicetable.h>
 #include <asm/chpid.h>
+#include <asm/cio.h>
+#include <asm/fcx.h>
+#include <asm/schid.h>
 #include "chsc.h"
-#include "schid.h"
 
 /*
  * path management control word
@@ -13,7 +16,7 @@
 struct pmcw {
        u32 intparm;            /* interruption parameter */
        u32 qf   : 1;           /* qdio facility */
-       u32 res0 : 1;           /* reserved zeros */
+       u32 w    : 1;
        u32 isc  : 3;           /* interruption sublass */
        u32 res5 : 3;           /* reserved zeros */
        u32 ena  : 1;           /* enabled */
@@ -47,7 +50,7 @@ struct pmcw {
  */
 struct schib {
        struct pmcw pmcw;        /* path management control word */
-       struct scsw scsw;        /* subchannel status word */
+       union scsw scsw;         /* subchannel status word */
        __u64 mba;               /* measurement block address */
        __u8 mda[4];             /* model dependent area */
 } __attribute__ ((packed,aligned(4)));
@@ -99,8 +102,11 @@ extern int cio_set_options (struct subchannel *, int);
 extern int cio_get_options (struct subchannel *);
 extern int cio_modify (struct subchannel *);
 
+int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
+int cio_tm_intrg(struct subchannel *sch);
+
 int cio_create_sch_lock(struct subchannel *);
-void do_adapter_IO(void);
+void do_adapter_IO(u8 isc);
 void do_IRQ(struct pt_regs *);
 
 /* Use with care. */
index 2808b6833b9edea7fceb7263017316e61dedbbd3..a90b28c0be5707f64bdd6a058ac416272756265c 100644 (file)
@@ -341,12 +341,12 @@ static int cmf_copy_block(struct ccw_device *cdev)
        if (stsch(sch->schid, &sch->schib))
                return -ENODEV;
 
-       if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
+       if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) {
                /* Don't copy if a start function is in progress. */
-               if ((!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) &&
-                   (sch->schib.scsw.actl &
+               if ((!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_SUSPENDED)) &&
+                   (scsw_actl(&sch->schib.scsw) &
                     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
-                   (!(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)))
+                   (!(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_SEC_STATUS)))
                        return -EBUSY;
        }
        cmb_data = cdev->private->cmb;
@@ -612,9 +612,6 @@ static int alloc_cmb(struct ccw_device *cdev)
                        free_pages((unsigned long)mem, get_order(size));
                } else if (!mem) {
                        /* no luck */
-                       printk(KERN_WARNING "cio: failed to allocate area "
-                              "for measuring %d subchannels\n",
-                              cmb_area.num_channels);
                        ret = -ENOMEM;
                        goto out;
                } else {
@@ -1230,13 +1227,9 @@ static ssize_t cmb_enable_store(struct device *dev,
        switch (val) {
        case 0:
                ret = disable_cmf(cdev);
-               if (ret)
-                       dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
                break;
        case 1:
                ret = enable_cmf(cdev);
-               if (ret && ret != -EBUSY)
-                       dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
                break;
        }
 
@@ -1344,8 +1337,7 @@ static int __init init_cmf(void)
         * to basic mode.
         */
        if (format == CMF_AUTODETECT) {
-               if (!css_characteristics_avail ||
-                   !css_general_characteristics.ext_mb) {
+               if (!css_general_characteristics.ext_mb) {
                        format = CMF_BASIC;
                } else {
                        format = CMF_EXTENDED;
@@ -1365,8 +1357,6 @@ static int __init init_cmf(void)
                cmbops = &cmbops_extended;
                break;
        default:
-               printk(KERN_ERR "cio: Invalid format %d for channel "
-                       "measurement facility\n", format);
                return 1;
        }
 
index a76956512b2d41963a0bd89ddba91a69f7b2553a..46c021d880dc5ee7441cd11f8e885bf54d79b7dd 100644 (file)
@@ -2,8 +2,7 @@
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                      IBM Corporation
+ *    Copyright IBM Corp. 2002,2008
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
  *              Cornelia Huck (cornelia.huck@de.ibm.com)
  */
@@ -14,7 +13,9 @@
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
+#include <asm/isc.h>
 
+#include "../s390mach.h"
 #include "css.h"
 #include "cio.h"
 #include "cio_debug.h"
@@ -30,8 +31,6 @@ static int max_ssid = 0;
 
 struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
 
-int css_characteristics_avail = 0;
-
 int
 for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
 {
@@ -121,25 +120,6 @@ css_alloc_subchannel(struct subchannel_id schid)
                kfree(sch);
                return ERR_PTR(ret);
        }
-
-       if (sch->st != SUBCHANNEL_TYPE_IO) {
-               /* For now we ignore all non-io subchannels. */
-               kfree(sch);
-               return ERR_PTR(-EINVAL);
-       }
-
-       /* 
-        * Set intparm to subchannel address.
-        * This is fine even on 64bit since the subchannel is always located
-        * under 2G.
-        */
-       sch->schib.pmcw.intparm = (u32)(addr_t)sch;
-       ret = cio_modify(sch);
-       if (ret) {
-               kfree(sch->lock);
-               kfree(sch);
-               return ERR_PTR(ret);
-       }
        return sch;
 }
 
@@ -177,12 +157,18 @@ static int css_sch_device_register(struct subchannel *sch)
        return ret;
 }
 
+/**
+ * css_sch_device_unregister - unregister a subchannel
+ * @sch: subchannel to be unregistered
+ */
 void css_sch_device_unregister(struct subchannel *sch)
 {
        mutex_lock(&sch->reg_mutex);
-       device_unregister(&sch->dev);
+       if (device_is_registered(&sch->dev))
+               device_unregister(&sch->dev);
        mutex_unlock(&sch->reg_mutex);
 }
+EXPORT_SYMBOL_GPL(css_sch_device_unregister);
 
 static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
 {
@@ -229,6 +215,41 @@ void css_update_ssd_info(struct subchannel *sch)
        }
 }
 
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct subchannel *sch = to_subchannel(dev);
+
+       return sprintf(buf, "%01x\n", sch->st);
+}
+
+static DEVICE_ATTR(type, 0444, type_show, NULL);
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct subchannel *sch = to_subchannel(dev);
+
+       return sprintf(buf, "css:t%01X\n", sch->st);
+}
+
+static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
+
+static struct attribute *subch_attrs[] = {
+       &dev_attr_type.attr,
+       &dev_attr_modalias.attr,
+       NULL,
+};
+
+static struct attribute_group subch_attr_group = {
+       .attrs = subch_attrs,
+};
+
+static struct attribute_group *default_subch_attr_groups[] = {
+       &subch_attr_group,
+       NULL,
+};
+
 static int css_register_subchannel(struct subchannel *sch)
 {
        int ret;
@@ -237,16 +258,17 @@ static int css_register_subchannel(struct subchannel *sch)
        sch->dev.parent = &channel_subsystems[0]->device;
        sch->dev.bus = &css_bus_type;
        sch->dev.release = &css_subchannel_release;
-       sch->dev.groups = subch_attr_groups;
+       sch->dev.groups = default_subch_attr_groups;
        /*
         * We don't want to generate uevents for I/O subchannels that don't
         * have a working ccw device behind them since they will be
         * unregistered before they can be used anyway, so we delay the add
         * uevent until after device recognition was successful.
+        * Note that we suppress the uevent for all subchannel types;
+        * the subchannel driver can decide itself when it wants to inform
+        * userspace of its existence.
         */
-       if (!cio_is_console(sch->schid))
-               /* Console is special, no need to suppress. */
-               sch->dev.uevent_suppress = 1;
+       sch->dev.uevent_suppress = 1;
        css_update_ssd_info(sch);
        /* make it known to the system */
        ret = css_sch_device_register(sch);
@@ -255,10 +277,19 @@ static int css_register_subchannel(struct subchannel *sch)
                              sch->schid.ssid, sch->schid.sch_no, ret);
                return ret;
        }
+       if (!sch->driver) {
+               /*
+                * No driver matched. Generate the uevent now so that
+                * a fitting driver module may be loaded based on the
+                * modalias.
+                */
+               sch->dev.uevent_suppress = 0;
+               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+       }
        return ret;
 }
 
-static int css_probe_device(struct subchannel_id schid)
+int css_probe_device(struct subchannel_id schid)
 {
        int ret;
        struct subchannel *sch;
@@ -301,116 +332,12 @@ int css_sch_is_valid(struct schib *schib)
 {
        if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
                return 0;
+       if ((schib->pmcw.st == SUBCHANNEL_TYPE_MSG) && !schib->pmcw.w)
+               return 0;
        return 1;
 }
 EXPORT_SYMBOL_GPL(css_sch_is_valid);
 
-static int css_get_subchannel_status(struct subchannel *sch)
-{
-       struct schib schib;
-
-       if (stsch(sch->schid, &schib))
-               return CIO_GONE;
-       if (!css_sch_is_valid(&schib))
-               return CIO_GONE;
-       if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
-               return CIO_REVALIDATE;
-       if (!sch->lpm)
-               return CIO_NO_PATH;
-       return CIO_OPER;
-}
-
-static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
-{
-       int event, ret, disc;
-       unsigned long flags;
-       enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
-
-       spin_lock_irqsave(sch->lock, flags);
-       disc = device_is_disconnected(sch);
-       if (disc && slow) {
-               /* Disconnected devices are evaluated directly only.*/
-               spin_unlock_irqrestore(sch->lock, flags);
-               return 0;
-       }
-       /* No interrupt after machine check - kill pending timers. */
-       device_kill_pending_timer(sch);
-       if (!disc && !slow) {
-               /* Non-disconnected devices are evaluated on the slow path. */
-               spin_unlock_irqrestore(sch->lock, flags);
-               return -EAGAIN;
-       }
-       event = css_get_subchannel_status(sch);
-       CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
-                     sch->schid.ssid, sch->schid.sch_no, event,
-                     disc ? "disconnected" : "normal",
-                     slow ? "slow" : "fast");
-       /* Analyze subchannel status. */
-       action = NONE;
-       switch (event) {
-       case CIO_NO_PATH:
-               if (disc) {
-                       /* Check if paths have become available. */
-                       action = REPROBE;
-                       break;
-               }
-               /* fall through */
-       case CIO_GONE:
-               /* Prevent unwanted effects when opening lock. */
-               cio_disable_subchannel(sch);
-               device_set_disconnected(sch);
-               /* Ask driver what to do with device. */
-               action = UNREGISTER;
-               if (sch->driver && sch->driver->notify) {
-                       spin_unlock_irqrestore(sch->lock, flags);
-                       ret = sch->driver->notify(sch, event);
-                       spin_lock_irqsave(sch->lock, flags);
-                       if (ret)
-                               action = NONE;
-               }
-               break;
-       case CIO_REVALIDATE:
-               /* Device will be removed, so no notify necessary. */
-               if (disc)
-                       /* Reprobe because immediate unregister might block. */
-                       action = REPROBE;
-               else
-                       action = UNREGISTER_PROBE;
-               break;
-       case CIO_OPER:
-               if (disc)
-                       /* Get device operational again. */
-                       action = REPROBE;
-               break;
-       }
-       /* Perform action. */
-       ret = 0;
-       switch (action) {
-       case UNREGISTER:
-       case UNREGISTER_PROBE:
-               /* Unregister device (will use subchannel lock). */
-               spin_unlock_irqrestore(sch->lock, flags);
-               css_sch_device_unregister(sch);
-               spin_lock_irqsave(sch->lock, flags);
-
-               /* Reset intparm to zeroes. */
-               sch->schib.pmcw.intparm = 0;
-               cio_modify(sch);
-               break;
-       case REPROBE:
-               device_trigger_reprobe(sch);
-               break;
-       default:
-               break;
-       }
-       spin_unlock_irqrestore(sch->lock, flags);
-       /* Probe if necessary. */
-       if (action == UNREGISTER_PROBE)
-               ret = css_probe_device(sch->schid);
-
-       return ret;
-}
-
 static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
 {
        struct schib schib;
@@ -429,6 +356,21 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
        return css_probe_device(schid);
 }
 
+static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
+{
+       int ret = 0;
+
+       if (sch->driver) {
+               if (sch->driver->sch_event)
+                       ret = sch->driver->sch_event(sch, slow);
+               else
+                       dev_dbg(&sch->dev,
+                               "Got subchannel machine check but "
+                               "no sch_event handler provided.\n");
+       }
+       return ret;
+}
+
 static void css_evaluate_subchannel(struct subchannel_id schid, int slow)
 {
        struct subchannel *sch;
@@ -596,18 +538,29 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe);
 /*
  * Called from the machine check handler for subchannel report words.
  */
-void css_process_crw(int rsid1, int rsid2)
+static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
 {
        struct subchannel_id mchk_schid;
 
-       CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n",
-                     rsid1, rsid2);
+       if (overflow) {
+               css_schedule_eval_all();
+               return;
+       }
+       CIO_CRW_EVENT(2, "CRW0 reports slct=%d, oflw=%d, "
+                     "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
+                     crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
+                     crw0->erc, crw0->rsid);
+       if (crw1)
+               CIO_CRW_EVENT(2, "CRW1 reports slct=%d, oflw=%d, "
+                             "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
+                             crw1->slct, crw1->oflw, crw1->chn, crw1->rsc,
+                             crw1->anc, crw1->erc, crw1->rsid);
        init_subchannel_id(&mchk_schid);
-       mchk_schid.sch_no = rsid1;
-       if (rsid2 != 0)
-               mchk_schid.ssid = (rsid2 >> 8) & 3;
+       mchk_schid.sch_no = crw0->rsid;
+       if (crw1)
+               mchk_schid.ssid = (crw1->rsid >> 8) & 3;
 
-       /* 
+       /*
         * Since we are always presented with IPI in the CRW, we have to
         * use stsch() to find out if the subchannel in question has come
         * or gone.
@@ -658,7 +611,7 @@ __init_channel_subsystem(struct subchannel_id schid, void *data)
 static void __init
 css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
 {
-       if (css_characteristics_avail && css_general_characteristics.mcss) {
+       if (css_general_characteristics.mcss) {
                css->global_pgid.pgid_high.ext_cssid.version = 0x80;
                css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
        } else {
@@ -795,8 +748,6 @@ init_channel_subsystem (void)
        ret = chsc_determine_css_characteristics();
        if (ret == -ENOMEM)
                goto out; /* No need to continue. */
-       if (ret == 0)
-               css_characteristics_avail = 1;
 
        ret = chsc_alloc_sei_area();
        if (ret)
@@ -806,6 +757,10 @@ init_channel_subsystem (void)
        if (ret)
                goto out;
 
+       ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw);
+       if (ret)
+               goto out;
+
        if ((ret = bus_register(&css_bus_type)))
                goto out;
 
@@ -836,8 +791,7 @@ init_channel_subsystem (void)
                ret = device_register(&css->device);
                if (ret)
                        goto out_free_all;
-               if (css_characteristics_avail &&
-                   css_chsc_characteristics.secm) {
+               if (css_chsc_characteristics.secm) {
                        ret = device_create_file(&css->device,
                                                 &dev_attr_cm_enable);
                        if (ret)
@@ -852,7 +806,8 @@ init_channel_subsystem (void)
                goto out_pseudo;
        css_init_done = 1;
 
-       ctl_set_bit(6, 28);
+       /* Enable default isc for I/O subchannels. */
+       isc_register(IO_SCH_ISC);
 
        for_each_subchannel(__init_channel_subsystem, NULL);
        return 0;
@@ -875,7 +830,7 @@ out_unregister:
                i--;
                css = channel_subsystems[i];
                device_unregister(&css->pseudo_subchannel->dev);
-               if (css_characteristics_avail && css_chsc_characteristics.secm)
+               if (css_chsc_characteristics.secm)
                        device_remove_file(&css->device,
                                           &dev_attr_cm_enable);
                device_unregister(&css->device);
@@ -883,6 +838,7 @@ out_unregister:
 out_bus:
        bus_unregister(&css_bus_type);
 out:
+       s390_unregister_crw_handler(CRW_RSC_CSS);
        chsc_free_sei_area();
        kfree(slow_subchannel_set);
        printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",
@@ -895,19 +851,16 @@ int sch_is_pseudo_sch(struct subchannel *sch)
        return sch == to_css(sch->dev.parent)->pseudo_subchannel;
 }
 
-/*
- * find a driver for a subchannel. They identify by the subchannel
- * type with the exception that the console subchannel driver has its own
- * subchannel type although the device is an i/o subchannel
- */
-static int
-css_bus_match (struct device *dev, struct device_driver *drv)
+static int css_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct subchannel *sch = to_subchannel(dev);
        struct css_driver *driver = to_cssdriver(drv);
+       struct css_device_id *id;
 
-       if (sch->st == driver->subchannel_type)
-               return 1;
+       for (id = driver->subchannel_type; id->match_flags; id++) {
+               if (sch->st == id->type)
+                       return 1;
+       }
 
        return 0;
 }
@@ -945,12 +898,25 @@ static void css_shutdown(struct device *dev)
                sch->driver->shutdown(sch);
 }
 
+static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       int ret;
+
+       ret = add_uevent_var(env, "ST=%01X", sch->st);
+       if (ret)
+               return ret;
+       ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st);
+       return ret;
+}
+
 struct bus_type css_bus_type = {
        .name     = "css",
        .match    = css_bus_match,
        .probe    = css_probe,
        .remove   = css_remove,
        .shutdown = css_shutdown,
+       .uevent   = css_uevent,
 };
 
 /**
@@ -985,4 +951,3 @@ subsys_initcall(init_channel_subsystem);
 
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(css_bus_type);
-EXPORT_SYMBOL_GPL(css_characteristics_avail);
index e1913518f354fff88d3508be92edb22d1ed330e8..57ebf120f825b00f68ee934e9e9a26324beedd09 100644 (file)
@@ -9,8 +9,7 @@
 
 #include <asm/cio.h>
 #include <asm/chpid.h>
-
-#include "schid.h"
+#include <asm/schid.h>
 
 /*
  * path grouping stuff
@@ -58,20 +57,28 @@ struct pgid {
        __u32 tod_high;         /* high word TOD clock */
 } __attribute__ ((packed));
 
-/*
- * A css driver handles all subchannels of one type.
- * Currently, we only care about I/O subchannels (type 0), these
- * have a ccw_device connected to them.
- */
 struct subchannel;
+struct chp_link;
+/**
+ * struct css_driver - device driver for subchannels
+ * @owner: owning module
+ * @subchannel_type: subchannel type supported by this driver
+ * @drv: embedded device driver structure
+ * @irq: called on interrupts
+ * @chp_event: called for events affecting a channel path
+ * @sch_event: called for events affecting the subchannel
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @shutdown: called at device shutdown
+ * @name: name of the device driver
+ */
 struct css_driver {
        struct module *owner;
-       unsigned int subchannel_type;
+       struct css_device_id *subchannel_type;
        struct device_driver drv;
        void (*irq)(struct subchannel *);
-       int (*notify)(struct subchannel *, int);
-       void (*verify)(struct subchannel *);
-       void (*termination)(struct subchannel *);
+       int (*chp_event)(struct subchannel *, struct chp_link *, int);
+       int (*sch_event)(struct subchannel *, int);
        int (*probe)(struct subchannel *);
        int (*remove)(struct subchannel *);
        void (*shutdown)(struct subchannel *);
@@ -89,13 +96,13 @@ extern int css_driver_register(struct css_driver *);
 extern void css_driver_unregister(struct css_driver *);
 
 extern void css_sch_device_unregister(struct subchannel *);
-extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
+extern int css_probe_device(struct subchannel_id);
+extern struct subchannel *get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
 int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
                               int (*fn_unknown)(struct subchannel_id,
                               void *), void *data);
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
-extern void css_process_crw(int, int);
 extern void css_reiterate_subchannels(void);
 void css_update_ssd_info(struct subchannel *sch);
 
@@ -121,20 +128,6 @@ struct channel_subsystem {
 extern struct bus_type css_bus_type;
 extern struct channel_subsystem *channel_subsystems[];
 
-/* Some helper functions for disconnected state. */
-int device_is_disconnected(struct subchannel *);
-void device_set_disconnected(struct subchannel *);
-void device_trigger_reprobe(struct subchannel *);
-
-/* Helper functions for vary on/off. */
-int device_is_online(struct subchannel *);
-void device_kill_io(struct subchannel *);
-void device_set_intretry(struct subchannel *sch);
-int device_trigger_verify(struct subchannel *sch);
-
-/* Machine check helper function. */
-void device_kill_pending_timer(struct subchannel *);
-
 /* Helper functions to build lists for the slow path. */
 void css_schedule_eval(struct subchannel_id schid);
 void css_schedule_eval_all(void);
@@ -145,6 +138,4 @@ int css_sch_is_valid(struct schib *);
 
 extern struct workqueue_struct *slow_path_wq;
 void css_wait_for_slow_path(void);
-
-extern struct attribute_group *subch_attr_groups[];
 #endif
index e22813db74a2b6bb81d2d0e1e27ec64acde946e2..e818d0c54c0949f5a21ae134ccf426da5d079d9c 100644 (file)
@@ -2,8 +2,7 @@
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                      IBM Corporation
+ *    Copyright IBM Corp. 2002,2008
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
  *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
@@ -23,7 +22,9 @@
 #include <asm/cio.h>
 #include <asm/param.h>         /* HZ */
 #include <asm/cmb.h>
+#include <asm/isc.h>
 
+#include "chp.h"
 #include "cio.h"
 #include "cio_debug.h"
 #include "css.h"
@@ -125,19 +126,24 @@ struct bus_type ccw_bus_type;
 static void io_subchannel_irq(struct subchannel *);
 static int io_subchannel_probe(struct subchannel *);
 static int io_subchannel_remove(struct subchannel *);
-static int io_subchannel_notify(struct subchannel *, int);
-static void io_subchannel_verify(struct subchannel *);
-static void io_subchannel_ioterm(struct subchannel *);
 static void io_subchannel_shutdown(struct subchannel *);
+static int io_subchannel_sch_event(struct subchannel *, int);
+static int io_subchannel_chp_event(struct subchannel *, struct chp_link *,
+                                  int);
+
+static struct css_device_id io_subchannel_ids[] = {
+       { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, },
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(css, io_subchannel_ids);
 
 static struct css_driver io_subchannel_driver = {
        .owner = THIS_MODULE,
-       .subchannel_type = SUBCHANNEL_TYPE_IO,
+       .subchannel_type = io_subchannel_ids,
        .name = "io_subchannel",
        .irq = io_subchannel_irq,
-       .notify = io_subchannel_notify,
-       .verify = io_subchannel_verify,
-       .termination = io_subchannel_ioterm,
+       .sch_event = io_subchannel_sch_event,
+       .chp_event = io_subchannel_chp_event,
        .probe = io_subchannel_probe,
        .remove = io_subchannel_remove,
        .shutdown = io_subchannel_shutdown,
@@ -487,25 +493,22 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
                ccw_device_set_online(cdev);
        return 0;
 }
-static void online_store_handle_online(struct ccw_device *cdev, int force)
+static int online_store_handle_online(struct ccw_device *cdev, int force)
 {
        int ret;
 
        ret = online_store_recog_and_online(cdev);
        if (ret)
-               return;
+               return ret;
        if (force && cdev->private->state == DEV_STATE_BOXED) {
                ret = ccw_device_stlck(cdev);
-               if (ret) {
-                       dev_warn(&cdev->dev,
-                                "ccw_device_stlck returned %d!\n", ret);
-                       return;
-               }
+               if (ret)
+                       return ret;
                if (cdev->id.cu_type == 0)
                        cdev->private->state = DEV_STATE_NOT_OPER;
                online_store_recog_and_online(cdev);
        }
-
+       return 0;
 }
 
 static ssize_t online_store (struct device *dev, struct device_attribute *attr,
@@ -538,8 +541,9 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
                ret = count;
                break;
        case 1:
-               online_store_handle_online(cdev, force);
-               ret = count;
+               ret = online_store_handle_online(cdev, force);
+               if (!ret)
+                       ret = count;
                break;
        default:
                ret = -EINVAL;
@@ -584,19 +588,14 @@ static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
 static DEVICE_ATTR(online, 0644, online_show, online_store);
 static DEVICE_ATTR(availability, 0444, available_show, NULL);
 
-static struct attribute * subch_attrs[] = {
+static struct attribute *io_subchannel_attrs[] = {
        &dev_attr_chpids.attr,
        &dev_attr_pimpampom.attr,
        NULL,
 };
 
-static struct attribute_group subch_attr_group = {
-       .attrs = subch_attrs,
-};
-
-struct attribute_group *subch_attr_groups[] = {
-       &subch_attr_group,
-       NULL,
+static struct attribute_group io_subchannel_attr_group = {
+       .attrs = io_subchannel_attrs,
 };
 
 static struct attribute * ccwdev_attrs[] = {
@@ -790,7 +789,7 @@ static void sch_attach_device(struct subchannel *sch,
        sch_set_cdev(sch, cdev);
        cdev->private->schid = sch->schid;
        cdev->ccwlock = sch->lock;
-       device_trigger_reprobe(sch);
+       ccw_device_trigger_reprobe(cdev);
        spin_unlock_irq(sch->lock);
 }
 
@@ -1037,7 +1036,6 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
        struct ccw_device_private *priv;
 
        sch_set_cdev(sch, cdev);
-       sch->driver = &io_subchannel_driver;
        cdev->ccwlock = sch->lock;
 
        /* Init private data. */
@@ -1122,8 +1120,33 @@ static void io_subchannel_irq(struct subchannel *sch)
                dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
 }
 
-static int
-io_subchannel_probe (struct subchannel *sch)
+static void io_subchannel_init_fields(struct subchannel *sch)
+{
+       if (cio_is_console(sch->schid))
+               sch->opm = 0xff;
+       else
+               sch->opm = chp_get_sch_opm(sch);
+       sch->lpm = sch->schib.pmcw.pam & sch->opm;
+       sch->isc = cio_is_console(sch->schid) ? CONSOLE_ISC : IO_SCH_ISC;
+
+       CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X"
+                     " - PIM = %02X, PAM = %02X, POM = %02X\n",
+                     sch->schib.pmcw.dev, sch->schid.ssid,
+                     sch->schid.sch_no, sch->schib.pmcw.pim,
+                     sch->schib.pmcw.pam, sch->schib.pmcw.pom);
+       /* Initially set up some fields in the pmcw. */
+       sch->schib.pmcw.ena = 0;
+       sch->schib.pmcw.csense = 1;     /* concurrent sense */
+       if ((sch->lpm & (sch->lpm - 1)) != 0)
+               sch->schib.pmcw.mp = 1; /* multipath mode */
+       /* clean up possible residual cmf stuff */
+       sch->schib.pmcw.mme = 0;
+       sch->schib.pmcw.mbfc = 0;
+       sch->schib.pmcw.mbi = 0;
+       sch->schib.mba = 0;
+}
+
+static int io_subchannel_probe(struct subchannel *sch)
 {
        struct ccw_device *cdev;
        int rc;
@@ -1132,11 +1155,21 @@ io_subchannel_probe (struct subchannel *sch)
 
        cdev = sch_get_cdev(sch);
        if (cdev) {
+               rc = sysfs_create_group(&sch->dev.kobj,
+                                       &io_subchannel_attr_group);
+               if (rc)
+                       CIO_MSG_EVENT(0, "Failed to create io subchannel "
+                                     "attributes for subchannel "
+                                     "0.%x.%04x (rc=%d)\n",
+                                     sch->schid.ssid, sch->schid.sch_no, rc);
                /*
                 * This subchannel already has an associated ccw_device.
-                * Register it and exit. This happens for all early
-                * device, e.g. the console.
+                * Throw the delayed uevent for the subchannel, register
+                * the ccw_device and exit. This happens for all early
+                * devices, e.g. the console.
                 */
+               sch->dev.uevent_suppress = 0;
+               kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
                cdev->dev.groups = ccwdev_attr_groups;
                device_initialize(&cdev->dev);
                ccw_device_register(cdev);
@@ -1152,17 +1185,24 @@ io_subchannel_probe (struct subchannel *sch)
                        get_device(&cdev->dev);
                return 0;
        }
+       io_subchannel_init_fields(sch);
        /*
         * First check if a fitting device may be found amongst the
         * disconnected devices or in the orphanage.
         */
        dev_id.devno = sch->schib.pmcw.dev;
        dev_id.ssid = sch->schid.ssid;
+       rc = sysfs_create_group(&sch->dev.kobj,
+                               &io_subchannel_attr_group);
+       if (rc)
+               return rc;
        /* Allocate I/O subchannel private data. */
        sch->private = kzalloc(sizeof(struct io_subchannel_private),
                               GFP_KERNEL | GFP_DMA);
-       if (!sch->private)
-               return -ENOMEM;
+       if (!sch->private) {
+               rc = -ENOMEM;
+               goto out_err;
+       }
        cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
        if (!cdev)
                cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1181,8 +1221,8 @@ io_subchannel_probe (struct subchannel *sch)
        }
        cdev = io_subchannel_create_ccwdev(sch);
        if (IS_ERR(cdev)) {
-               kfree(sch->private);
-               return PTR_ERR(cdev);
+               rc = PTR_ERR(cdev);
+               goto out_err;
        }
        rc = io_subchannel_recog(cdev, sch);
        if (rc) {
@@ -1191,9 +1231,12 @@ io_subchannel_probe (struct subchannel *sch)
                spin_unlock_irqrestore(sch->lock, flags);
                if (cdev->dev.release)
                        cdev->dev.release(&cdev->dev);
-               kfree(sch->private);
+               goto out_err;
        }
-
+       return 0;
+out_err:
+       kfree(sch->private);
+       sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
        return rc;
 }
 
@@ -1214,6 +1257,7 @@ io_subchannel_remove (struct subchannel *sch)
        ccw_device_unregister(cdev);
        put_device(&cdev->dev);
        kfree(sch->private);
+       sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
        return 0;
 }
 
@@ -1224,11 +1268,7 @@ static int io_subchannel_notify(struct subchannel *sch, int event)
        cdev = sch_get_cdev(sch);
        if (!cdev)
                return 0;
-       if (!cdev->drv)
-               return 0;
-       if (!cdev->online)
-               return 0;
-       return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
+       return ccw_device_notify(cdev, event);
 }
 
 static void io_subchannel_verify(struct subchannel *sch)
@@ -1240,22 +1280,96 @@ static void io_subchannel_verify(struct subchannel *sch)
                dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 }
 
-static void io_subchannel_ioterm(struct subchannel *sch)
+static int check_for_io_on_path(struct subchannel *sch, int mask)
 {
-       struct ccw_device *cdev;
+       int cc;
 
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return;
-       /* Internal I/O will be retried by the interrupt handler. */
-       if (cdev->private->flags.intretry)
+       cc = stsch(sch->schid, &sch->schib);
+       if (cc)
+               return 0;
+       if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask)
+               return 1;
+       return 0;
+}
+
+static void terminate_internal_io(struct subchannel *sch,
+                                 struct ccw_device *cdev)
+{
+       if (cio_clear(sch)) {
+               /* Recheck device in case clear failed. */
+               sch->lpm = 0;
+               if (cdev->online)
+                       dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+               else
+                       css_schedule_eval(sch->schid);
                return;
+       }
        cdev->private->state = DEV_STATE_CLEAR_VERIFY;
+       /* Request retry of internal operation. */
+       cdev->private->flags.intretry = 1;
+       /* Call handler. */
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
                              ERR_PTR(-EIO));
 }
 
+static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask)
+{
+       struct ccw_device *cdev;
+
+       cdev = sch_get_cdev(sch);
+       if (!cdev)
+               return;
+       if (check_for_io_on_path(sch, mask)) {
+               if (cdev->private->state == DEV_STATE_ONLINE)
+                       ccw_device_kill_io(cdev);
+               else {
+                       terminate_internal_io(sch, cdev);
+                       /* Re-start path verification. */
+                       dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+               }
+       } else
+               /* trigger path verification. */
+               dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+
+}
+
+static int io_subchannel_chp_event(struct subchannel *sch,
+                                  struct chp_link *link, int event)
+{
+       int mask;
+
+       mask = chp_ssd_get_mask(&sch->ssd_info, link);
+       if (!mask)
+               return 0;
+       switch (event) {
+       case CHP_VARY_OFF:
+               sch->opm &= ~mask;
+               sch->lpm &= ~mask;
+               io_subchannel_terminate_path(sch, mask);
+               break;
+       case CHP_VARY_ON:
+               sch->opm |= mask;
+               sch->lpm |= mask;
+               io_subchannel_verify(sch);
+               break;
+       case CHP_OFFLINE:
+               if (stsch(sch->schid, &sch->schib))
+                       return -ENXIO;
+               if (!css_sch_is_valid(&sch->schib))
+                       return -ENODEV;
+               io_subchannel_terminate_path(sch, mask);
+               break;
+       case CHP_ONLINE:
+               if (stsch(sch->schid, &sch->schib))
+                       return -ENXIO;
+               sch->lpm |= mask & sch->opm;
+               io_subchannel_verify(sch);
+               break;
+       }
+       return 0;
+}
+
 static void
 io_subchannel_shutdown(struct subchannel *sch)
 {
@@ -1285,6 +1399,195 @@ io_subchannel_shutdown(struct subchannel *sch)
        cio_disable_subchannel(sch);
 }
 
+static int io_subchannel_get_status(struct subchannel *sch)
+{
+       struct schib schib;
+
+       if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
+               return CIO_GONE;
+       if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
+               return CIO_REVALIDATE;
+       if (!sch->lpm)
+               return CIO_NO_PATH;
+       return CIO_OPER;
+}
+
+static int device_is_disconnected(struct ccw_device *cdev)
+{
+       if (!cdev)
+               return 0;
+       return (cdev->private->state == DEV_STATE_DISCONNECTED ||
+               cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
+}
+
+static int recovery_check(struct device *dev, void *data)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       int *redo = data;
+
+       spin_lock_irq(cdev->ccwlock);
+       switch (cdev->private->state) {
+       case DEV_STATE_DISCONNECTED:
+               CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+                             cdev->private->dev_id.ssid,
+                             cdev->private->dev_id.devno);
+               dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+               *redo = 1;
+               break;
+       case DEV_STATE_DISCONNECTED_SENSE_ID:
+               *redo = 1;
+               break;
+       }
+       spin_unlock_irq(cdev->ccwlock);
+
+       return 0;
+}
+
+static void recovery_work_func(struct work_struct *unused)
+{
+       int redo = 0;
+
+       bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
+       if (redo) {
+               spin_lock_irq(&recovery_lock);
+               if (!timer_pending(&recovery_timer)) {
+                       if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
+                               recovery_phase++;
+                       mod_timer(&recovery_timer, jiffies +
+                                 recovery_delay[recovery_phase] * HZ);
+               }
+               spin_unlock_irq(&recovery_lock);
+       } else
+               CIO_MSG_EVENT(4, "recovery: end\n");
+}
+
+static DECLARE_WORK(recovery_work, recovery_work_func);
+
+static void recovery_func(unsigned long data)
+{
+       /*
+        * We can't do our recovery in softirq context and it's not
+        * performance critical, so we schedule it.
+        */
+       schedule_work(&recovery_work);
+}
+
+static void ccw_device_schedule_recovery(void)
+{
+       unsigned long flags;
+
+       CIO_MSG_EVENT(4, "recovery: schedule\n");
+       spin_lock_irqsave(&recovery_lock, flags);
+       if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
+               recovery_phase = 0;
+               mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
+       }
+       spin_unlock_irqrestore(&recovery_lock, flags);
+}
+
+static void device_set_disconnected(struct ccw_device *cdev)
+{
+       if (!cdev)
+               return;
+       ccw_device_set_timeout(cdev, 0);
+       cdev->private->flags.fake_irb = 0;
+       cdev->private->state = DEV_STATE_DISCONNECTED;
+       if (cdev->online)
+               ccw_device_schedule_recovery();
+}
+
+static int io_subchannel_sch_event(struct subchannel *sch, int slow)
+{
+       int event, ret, disc;
+       unsigned long flags;
+       enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
+       struct ccw_device *cdev;
+
+       spin_lock_irqsave(sch->lock, flags);
+       cdev = sch_get_cdev(sch);
+       disc = device_is_disconnected(cdev);
+       if (disc && slow) {
+               /* Disconnected devices are evaluated directly only.*/
+               spin_unlock_irqrestore(sch->lock, flags);
+               return 0;
+       }
+       /* No interrupt after machine check - kill pending timers. */
+       if (cdev)
+               ccw_device_set_timeout(cdev, 0);
+       if (!disc && !slow) {
+               /* Non-disconnected devices are evaluated on the slow path. */
+               spin_unlock_irqrestore(sch->lock, flags);
+               return -EAGAIN;
+       }
+       event = io_subchannel_get_status(sch);
+       CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
+                     sch->schid.ssid, sch->schid.sch_no, event,
+                     disc ? "disconnected" : "normal",
+                     slow ? "slow" : "fast");
+       /* Analyze subchannel status. */
+       action = NONE;
+       switch (event) {
+       case CIO_NO_PATH:
+               if (disc) {
+                       /* Check if paths have become available. */
+                       action = REPROBE;
+                       break;
+               }
+               /* fall through */
+       case CIO_GONE:
+               /* Prevent unwanted effects when opening lock. */
+               cio_disable_subchannel(sch);
+               device_set_disconnected(cdev);
+               /* Ask driver what to do with device. */
+               action = UNREGISTER;
+               spin_unlock_irqrestore(sch->lock, flags);
+               ret = io_subchannel_notify(sch, event);
+               spin_lock_irqsave(sch->lock, flags);
+               if (ret)
+                       action = NONE;
+               break;
+       case CIO_REVALIDATE:
+               /* Device will be removed, so no notify necessary. */
+               if (disc)
+                       /* Reprobe because immediate unregister might block. */
+                       action = REPROBE;
+               else
+                       action = UNREGISTER_PROBE;
+               break;
+       case CIO_OPER:
+               if (disc)
+                       /* Get device operational again. */
+                       action = REPROBE;
+               break;
+       }
+       /* Perform action. */
+       ret = 0;
+       switch (action) {
+       case UNREGISTER:
+       case UNREGISTER_PROBE:
+               /* Unregister device (will use subchannel lock). */
+               spin_unlock_irqrestore(sch->lock, flags);
+               css_sch_device_unregister(sch);
+               spin_lock_irqsave(sch->lock, flags);
+
+               /* Reset intparm to zeroes. */
+               sch->schib.pmcw.intparm = 0;
+               cio_modify(sch);
+               break;
+       case REPROBE:
+               ccw_device_trigger_reprobe(cdev);
+               break;
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(sch->lock, flags);
+       /* Probe if necessary. */
+       if (action == UNREGISTER_PROBE)
+               ret = css_probe_device(sch->schid);
+
+       return ret;
+}
+
 #ifdef CONFIG_CCW_CONSOLE
 static struct ccw_device console_cdev;
 static struct ccw_device_private console_private;
@@ -1297,14 +1600,16 @@ spinlock_t * cio_get_console_lock(void)
        return &ccw_console_lock;
 }
 
-static int
-ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
+static int ccw_device_console_enable(struct ccw_device *cdev,
+                                    struct subchannel *sch)
 {
        int rc;
 
        /* Attach subchannel private data. */
        sch->private = cio_get_console_priv();
        memset(sch->private, 0, sizeof(struct io_subchannel_private));
+       io_subchannel_init_fields(sch);
+       sch->driver = &io_subchannel_driver;
        /* Initialize the ccw_device structure. */
        cdev->dev.parent= &sch->dev;
        rc = io_subchannel_recog(cdev, sch);
@@ -1515,71 +1820,6 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
        return sch->schid;
 }
 
-static int recovery_check(struct device *dev, void *data)
-{
-       struct ccw_device *cdev = to_ccwdev(dev);
-       int *redo = data;
-
-       spin_lock_irq(cdev->ccwlock);
-       switch (cdev->private->state) {
-       case DEV_STATE_DISCONNECTED:
-               CIO_MSG_EVENT(4, "recovery: trigger 0.%x.%04x\n",
-                             cdev->private->dev_id.ssid,
-                             cdev->private->dev_id.devno);
-               dev_fsm_event(cdev, DEV_EVENT_VERIFY);
-               *redo = 1;
-               break;
-       case DEV_STATE_DISCONNECTED_SENSE_ID:
-               *redo = 1;
-               break;
-       }
-       spin_unlock_irq(cdev->ccwlock);
-
-       return 0;
-}
-
-static void recovery_work_func(struct work_struct *unused)
-{
-       int redo = 0;
-
-       bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
-       if (redo) {
-               spin_lock_irq(&recovery_lock);
-               if (!timer_pending(&recovery_timer)) {
-                       if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
-                               recovery_phase++;
-                       mod_timer(&recovery_timer, jiffies +
-                                 recovery_delay[recovery_phase] * HZ);
-               }
-               spin_unlock_irq(&recovery_lock);
-       } else
-               CIO_MSG_EVENT(4, "recovery: end\n");
-}
-
-static DECLARE_WORK(recovery_work, recovery_work_func);
-
-static void recovery_func(unsigned long data)
-{
-       /*
-        * We can't do our recovery in softirq context and it's not
-        * performance critical, so we schedule it.
-        */
-       schedule_work(&recovery_work);
-}
-
-void ccw_device_schedule_recovery(void)
-{
-       unsigned long flags;
-
-       CIO_MSG_EVENT(4, "recovery: schedule\n");
-       spin_lock_irqsave(&recovery_lock, flags);
-       if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
-               recovery_phase = 0;
-               mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
-       }
-       spin_unlock_irqrestore(&recovery_lock, flags);
-}
-
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
index cb08092be39f0e29b3e6218f04c7ef86af27289f..9800a8335a3fa81a195b9c5b3ae83380c21ae5ef 100644 (file)
@@ -88,8 +88,6 @@ int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
 
-void ccw_device_schedule_recovery(void);
-
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
 void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
@@ -118,6 +116,11 @@ int ccw_device_call_handler(struct ccw_device *);
 
 int ccw_device_stlck(struct ccw_device *);
 
+/* Helper function for machine check handling. */
+void ccw_device_trigger_reprobe(struct ccw_device *);
+void ccw_device_kill_io(struct ccw_device *);
+int ccw_device_notify(struct ccw_device *, int);
+
 /* qdio needs this. */
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
index e268d5a77c12633c4d80d5493add727229fe94fa..8b5fe57fb2f31ef1684d586aca9f69c9c9e4fab3 100644 (file)
@@ -2,8 +2,7 @@
  * drivers/s390/cio/device_fsm.c
  * finite state machine for device handling
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                      IBM Corporation
+ *    Copyright IBM Corp. 2002,2008
  *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
 static int timeout_log_enabled;
 
-int
-device_is_online(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return 0;
-       return (cdev->private->state == DEV_STATE_ONLINE);
-}
-
-int
-device_is_disconnected(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return 0;
-       return (cdev->private->state == DEV_STATE_DISCONNECTED ||
-               cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
-}
-
-void
-device_set_disconnected(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return;
-       ccw_device_set_timeout(cdev, 0);
-       cdev->private->flags.fake_irb = 0;
-       cdev->private->state = DEV_STATE_DISCONNECTED;
-       if (cdev->online)
-               ccw_device_schedule_recovery();
-}
-
-void device_set_intretry(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return;
-       cdev->private->flags.intretry = 1;
-}
-
-int device_trigger_verify(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       cdev = sch_get_cdev(sch);
-       if (!cdev || !cdev->online)
-               return -EINVAL;
-       dev_fsm_event(cdev, DEV_EVENT_VERIFY);
-       return 0;
-}
-
 static int __init ccw_timeout_log_setup(char *unused)
 {
        timeout_log_enabled = 1;
@@ -99,31 +39,43 @@ static void ccw_timeout_log(struct ccw_device *cdev)
        struct schib schib;
        struct subchannel *sch;
        struct io_subchannel_private *private;
+       union orb *orb;
        int cc;
 
        sch = to_subchannel(cdev->dev.parent);
        private = to_io_private(sch);
+       orb = &private->orb;
        cc = stsch(sch->schid, &schib);
 
        printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
               "device information:\n", get_clock());
        printk(KERN_WARNING "cio: orb:\n");
        print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-                      &private->orb, sizeof(private->orb), 0);
+                      orb, sizeof(*orb), 0);
        printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
        printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
        printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
               "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
 
-       if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
-           (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
-               printk(KERN_WARNING "cio: last channel program (intern):\n");
-       else
-               printk(KERN_WARNING "cio: last channel program:\n");
-
-       print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-                      (void *)(addr_t)private->orb.cpa,
-                      sizeof(struct ccw1), 0);
+       if (orb->tm.b) {
+               printk(KERN_WARNING "cio: orb indicates transport mode\n");
+               printk(KERN_WARNING "cio: last tcw:\n");
+               print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+                              (void *)(addr_t)orb->tm.tcw,
+                              sizeof(struct tcw), 0);
+       } else {
+               printk(KERN_WARNING "cio: orb indicates command mode\n");
+               if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw ||
+                   (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws)
+                       printk(KERN_WARNING "cio: last channel program "
+                              "(intern):\n");
+               else
+                       printk(KERN_WARNING "cio: last channel program:\n");
+
+               print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+                              (void *)(addr_t)orb->cmd.cpa,
+                              sizeof(struct ccw1), 0);
+       }
        printk(KERN_WARNING "cio: ccw device state: %d\n",
               cdev->private->state);
        printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
@@ -171,18 +123,6 @@ ccw_device_set_timeout(struct ccw_device *cdev, int expires)
        add_timer(&cdev->private->timer);
 }
 
-/* Kill any pending timers after machine check. */
-void
-device_kill_pending_timer(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return;
-       ccw_device_set_timeout(cdev, 0);
-}
-
 /*
  * Cancel running i/o. This is called repeatedly since halt/clear are
  * asynchronous operations. We do one try with cio_cancel, two tries
@@ -205,15 +145,18 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
                /* Not operational -> done. */
                return 0;
        /* Stage 1: cancel io. */
-       if (!(sch->schib.scsw.actl & SCSW_ACTL_HALT_PEND) &&
-           !(sch->schib.scsw.actl & SCSW_ACTL_CLEAR_PEND)) {
-               ret = cio_cancel(sch);
-               if (ret != -EINVAL)
-                       return ret;
-               /* cancel io unsuccessful. From now on it is asynchronous. */
+       if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) &&
+           !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
+               if (!scsw_is_tm(&sch->schib.scsw)) {
+                       ret = cio_cancel(sch);
+                       if (ret != -EINVAL)
+                               return ret;
+               }
+               /* cancel io unsuccessful or not applicable (transport mode).
+                * Continue with asynchronous instructions. */
                cdev->private->iretry = 3;      /* 3 halt retries. */
        }
-       if (!(sch->schib.scsw.actl & SCSW_ACTL_CLEAR_PEND)) {
+       if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
                /* Stage 2: halt io. */
                if (cdev->private->iretry) {
                        cdev->private->iretry--;
@@ -388,34 +331,30 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err)
        }
 }
 
+int ccw_device_notify(struct ccw_device *cdev, int event)
+{
+       if (!cdev->drv)
+               return 0;
+       if (!cdev->online)
+               return 0;
+       return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
+}
+
 static void
 ccw_device_oper_notify(struct work_struct *work)
 {
        struct ccw_device_private *priv;
        struct ccw_device *cdev;
-       struct subchannel *sch;
        int ret;
-       unsigned long flags;
 
        priv = container_of(work, struct ccw_device_private, kick_work);
        cdev = priv->cdev;
-       spin_lock_irqsave(cdev->ccwlock, flags);
-       sch = to_subchannel(cdev->dev.parent);
-       if (sch->driver && sch->driver->notify) {
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
-               ret = sch->driver->notify(sch, CIO_OPER);
-               spin_lock_irqsave(cdev->ccwlock, flags);
-       } else
-               ret = 0;
+       ret = ccw_device_notify(cdev, CIO_OPER);
        if (ret) {
                /* Reenable channel measurements, if needed. */
-               spin_unlock_irqrestore(cdev->ccwlock, flags);
                cmf_reenable(cdev);
-               spin_lock_irqsave(cdev->ccwlock, flags);
                wake_up(&cdev->private->wait_q);
-       }
-       spin_unlock_irqrestore(cdev->ccwlock, flags);
-       if (!ret)
+       } else
                /* Driver doesn't want device back. */
                ccw_device_do_unreg_rereg(work);
 }
@@ -621,10 +560,11 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
                /* Deliver fake irb to device driver, if needed. */
                if (cdev->private->flags.fake_irb) {
                        memset(&cdev->private->irb, 0, sizeof(struct irb));
-                       cdev->private->irb.scsw.cc = 1;
-                       cdev->private->irb.scsw.fctl = SCSW_FCTL_START_FUNC;
-                       cdev->private->irb.scsw.actl = SCSW_ACTL_START_PEND;
-                       cdev->private->irb.scsw.stctl = SCSW_STCTL_STATUS_PEND;
+                       cdev->private->irb.scsw.cmd.cc = 1;
+                       cdev->private->irb.scsw.cmd.fctl = SCSW_FCTL_START_FUNC;
+                       cdev->private->irb.scsw.cmd.actl = SCSW_ACTL_START_PEND;
+                       cdev->private->irb.scsw.cmd.stctl =
+                               SCSW_STCTL_STATUS_PEND;
                        cdev->private->flags.fake_irb = 0;
                        if (cdev->handler)
                                cdev->handler(cdev, cdev->private->intparm,
@@ -718,13 +658,10 @@ ccw_device_offline(struct ccw_device *cdev)
        sch = to_subchannel(cdev->dev.parent);
        if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
                return -ENODEV;
-       if (cdev->private->state != DEV_STATE_ONLINE) {
-               if (sch->schib.scsw.actl != 0)
-                       return -EBUSY;
-               return -EINVAL;
-       }
-       if (sch->schib.scsw.actl != 0)
+       if (scsw_actl(&sch->schib.scsw) != 0)
                return -EBUSY;
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               return -EINVAL;
        /* Are we doing path grouping? */
        if (!cdev->private->options.pgroup) {
                /* No, set state offline immediately. */
@@ -799,9 +736,9 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
         */
        stsch(sch->schid, &sch->schib);
 
-       if (sch->schib.scsw.actl != 0 ||
-           (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) ||
-           (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
+       if (scsw_actl(&sch->schib.scsw) != 0 ||
+           (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) ||
+           (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) {
                /*
                 * No final status yet or final status not yet delivered
                 * to the device driver. Can't do path verfication now,
@@ -823,13 +760,13 @@ static void
 ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
 {
        struct irb *irb;
+       int is_cmd;
 
        irb = (struct irb *) __LC_IRB;
+       is_cmd = !scsw_is_tm(&irb->scsw);
        /* Check for unsolicited interrupt. */
-       if ((irb->scsw.stctl ==
-                       (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
-           && (!irb->scsw.cc)) {
-               if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+       if (!scsw_is_solicited(&irb->scsw)) {
+               if (is_cmd && (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
                    !irb->esw.esw0.erw.cons) {
                        /* Unit check but no sense data. Need basic sense. */
                        if (ccw_device_do_sense(cdev, irb) != 0)
@@ -848,7 +785,7 @@ call_handler_unsol:
        }
        /* Accumulate status and find out if a basic sense is needed. */
        ccw_device_accumulate_irb(cdev, irb);
-       if (cdev->private->flags.dosense) {
+       if (is_cmd && cdev->private->flags.dosense) {
                if (ccw_device_do_sense(cdev, irb) == 0) {
                        cdev->private->state = DEV_STATE_W4SENSE;
                }
@@ -892,9 +829,9 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
 
        irb = (struct irb *) __LC_IRB;
        /* Check for unsolicited interrupt. */
-       if (irb->scsw.stctl ==
-                       (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-               if (irb->scsw.cc == 1)
+       if (scsw_stctl(&irb->scsw) ==
+           (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
+               if (scsw_cc(&irb->scsw) == 1)
                        /* Basic sense hasn't started. Try again. */
                        ccw_device_do_sense(cdev, irb);
                else {
@@ -912,7 +849,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
         * only deliver the halt/clear interrupt to the device driver as if it
         * had killed the original request.
         */
-       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
+       if (scsw_fctl(&irb->scsw) &
+           (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
                /* Retry Basic Sense if requested. */
                if (cdev->private->flags.intretry) {
                        cdev->private->flags.intretry = 0;
@@ -986,12 +924,10 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                              ERR_PTR(-EIO));
 }
 
-void device_kill_io(struct subchannel *sch)
+void ccw_device_kill_io(struct ccw_device *cdev)
 {
        int ret;
-       struct ccw_device *cdev;
 
-       cdev = sch_get_cdev(sch);
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
@@ -1021,9 +957,9 @@ ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event)
        case DEV_EVENT_INTERRUPT:
                irb = (struct irb *) __LC_IRB;
                /* Check for unsolicited interrupt. */
-               if ((irb->scsw.stctl ==
+               if ((scsw_stctl(&irb->scsw) ==
                     (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
-                   (!irb->scsw.cc))
+                   (!scsw_cc(&irb->scsw)))
                        /* FIXME: we should restart stlck here, but this
                         * is extremely unlikely ... */
                        goto out_wakeup;
@@ -1055,17 +991,14 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
        ccw_device_sense_id_start(cdev);
 }
 
-void
-device_trigger_reprobe(struct subchannel *sch)
+void ccw_device_trigger_reprobe(struct ccw_device *cdev)
 {
-       struct ccw_device *cdev;
+       struct subchannel *sch;
 
-       cdev = sch_get_cdev(sch);
-       if (!cdev)
-               return;
        if (cdev->private->state != DEV_STATE_DISCONNECTED)
                return;
 
+       sch = to_subchannel(cdev->dev.parent);
        /* Update some values. */
        if (stsch(sch->schid, &sch->schib))
                return;
@@ -1081,7 +1014,6 @@ device_trigger_reprobe(struct subchannel *sch)
        sch->schib.pmcw.ena = 0;
        if ((sch->lpm & (sch->lpm - 1)) != 0)
                sch->schib.pmcw.mp = 1;
-       sch->schib.pmcw.intparm = (u32)(addr_t)sch;
        /* We should also udate ssd info, but this has to wait. */
        /* Check if this is another device which appeared on the same sch. */
        if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
index cba7020517edbaa300e5fd2cfc3b80d52380aea3..1bdaa614e34fef0dbebe6d6f5f03aa7de7ed25a9 100644 (file)
@@ -196,7 +196,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
        irb = &cdev->private->irb;
 
        /* Check the error cases. */
-       if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
+       if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
                /* Retry Sense ID if requested. */
                if (cdev->private->flags.intretry) {
                        cdev->private->flags.intretry = 0;
@@ -234,10 +234,10 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
                              irb->ecw[6], irb->ecw[7]);
                return -EAGAIN;
        }
-       if (irb->scsw.cc == 3) {
+       if (irb->scsw.cmd.cc == 3) {
                u8 lpm;
 
-               lpm = to_io_private(sch)->orb.lpm;
+               lpm = to_io_private(sch)->orb.cmd.lpm;
                if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
                        CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x "
                                      "on subchannel 0.%x.%04x is "
@@ -248,9 +248,9 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
        }
 
        /* Did we get a proper answer ? */
-       if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
+       if (irb->scsw.cmd.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
            cdev->private->senseid.reserved == 0xFF) {
-               if (irb->scsw.count < sizeof(struct senseid) - 8)
+               if (irb->scsw.cmd.count < sizeof(struct senseid) - 8)
                        cdev->private->flags.esid = 1;
                return 0; /* Success */
        }
@@ -260,7 +260,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
                      "subchannel 0.%x.%04x returns status %02X%02X\n",
                      cdev->private->dev_id.devno, sch->schid.ssid,
                      sch->schid.sch_no,
-                     irb->scsw.dstat, irb->scsw.cstat);
+                     irb->scsw.cmd.dstat, irb->scsw.cmd.cstat);
        return -EAGAIN;
 }
 
@@ -277,9 +277,9 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
        sch = to_subchannel(cdev->dev.parent);
        irb = (struct irb *) __LC_IRB;
        /* Retry sense id, if needed. */
-       if (irb->scsw.stctl ==
+       if (irb->scsw.cmd.stctl ==
            (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-               if ((irb->scsw.cc == 1) || !irb->scsw.actl) {
+               if ((irb->scsw.cmd.cc == 1) || !irb->scsw.cmd.actl) {
                        ret = __ccw_device_sense_id_start(cdev);
                        if (ret && ret != -EBUSY)
                                ccw_device_sense_id_done(cdev, ret);
index f308ad55a6d5bed173b2fc5ee71197069bd764cc..ee1a28310fbb11945c07714fc9dfef94b4a20752 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/ccwdev.h>
 #include <asm/idals.h>
 #include <asm/chpid.h>
+#include <asm/fcx.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -179,8 +180,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
                        return -EBUSY;
        }
        if (cdev->private->state != DEV_STATE_ONLINE ||
-           ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
-            !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
+           ((sch->schib.scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) &&
+            !(sch->schib.scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS)) ||
            cdev->private->flags.doverify)
                return -EBUSY;
        ret = cio_set_options (sch, flags);
@@ -379,7 +380,7 @@ int ccw_device_resume(struct ccw_device *cdev)
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE ||
-           !(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED))
+           !(sch->schib.scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
                return -EINVAL;
        return cio_resume(sch);
 }
@@ -404,7 +405,7 @@ ccw_device_call_handler(struct ccw_device *cdev)
         *  - fast notification was requested (primary status)
         *  - unsolicited interrupts
         */
-       stctl = cdev->private->irb.scsw.stctl;
+       stctl = scsw_stctl(&cdev->private->irb.scsw);
        ending_status = (stctl & SCSW_STCTL_SEC_STATUS) ||
                (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) ||
                (stctl == SCSW_STCTL_STATUS_PEND);
@@ -528,14 +529,15 @@ ccw_device_stlck(struct ccw_device *cdev)
                cio_disable_subchannel(sch); //FIXME: return code?
                goto out_unlock;
        }
-       cdev->private->irb.scsw.actl |= SCSW_ACTL_START_PEND;
+       cdev->private->irb.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
        spin_unlock_irqrestore(sch->lock, flags);
-       wait_event(cdev->private->wait_q, cdev->private->irb.scsw.actl == 0);
+       wait_event(cdev->private->wait_q,
+                  cdev->private->irb.scsw.cmd.actl == 0);
        spin_lock_irqsave(sch->lock, flags);
        cio_disable_subchannel(sch); //FIXME: return code?
-       if ((cdev->private->irb.scsw.dstat !=
+       if ((cdev->private->irb.scsw.cmd.dstat !=
             (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-           (cdev->private->irb.scsw.cstat != 0))
+           (cdev->private->irb.scsw.cmd.cstat != 0))
                ret = -EIO;
        /* Clear irb. */
        memset(&cdev->private->irb, 0, sizeof(struct irb));
@@ -568,6 +570,122 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id)
 }
 EXPORT_SYMBOL(ccw_device_get_id);
 
+/**
+ * ccw_device_tm_start_key - perform start function
+ * @cdev: ccw device on which to perform the start function
+ * @tcw: transport-command word to be started
+ * @intparm: user defined parameter to be passed to the interrupt handler
+ * @lpm: mask of paths to use
+ * @key: storage key to use for storage access
+ *
+ * Start the tcw on the given ccw device. Return zero on success, non-zero
+ * otherwise.
+ */
+int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
+                           unsigned long intparm, u8 lpm, u8 key)
+{
+       struct subchannel *sch;
+       int rc;
+
+       sch = to_subchannel(cdev->dev.parent);
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               return -EIO;
+       /* Adjust requested path mask to excluded varied off paths. */
+       if (lpm) {
+               lpm &= sch->opm;
+               if (lpm == 0)
+                       return -EACCES;
+       }
+       rc = cio_tm_start_key(sch, tcw, lpm, key);
+       if (rc == 0)
+               cdev->private->intparm = intparm;
+       return rc;
+}
+EXPORT_SYMBOL(ccw_device_tm_start_key);
+
+/**
+ * ccw_device_tm_start_timeout_key - perform start function
+ * @cdev: ccw device on which to perform the start function
+ * @tcw: transport-command word to be started
+ * @intparm: user defined parameter to be passed to the interrupt handler
+ * @lpm: mask of paths to use
+ * @key: storage key to use for storage access
+ * @expires: time span in jiffies after which to abort request
+ *
+ * Start the tcw on the given ccw device. Return zero on success, non-zero
+ * otherwise.
+ */
+int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
+                                   unsigned long intparm, u8 lpm, u8 key,
+                                   int expires)
+{
+       int ret;
+
+       ccw_device_set_timeout(cdev, expires);
+       ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key);
+       if (ret != 0)
+               ccw_device_set_timeout(cdev, 0);
+       return ret;
+}
+EXPORT_SYMBOL(ccw_device_tm_start_timeout_key);
+
+/**
+ * ccw_device_tm_start - perform start function
+ * @cdev: ccw device on which to perform the start function
+ * @tcw: transport-command word to be started
+ * @intparm: user defined parameter to be passed to the interrupt handler
+ * @lpm: mask of paths to use
+ *
+ * Start the tcw on the given ccw device. Return zero on success, non-zero
+ * otherwise.
+ */
+int ccw_device_tm_start(struct ccw_device *cdev, struct tcw *tcw,
+                       unsigned long intparm, u8 lpm)
+{
+       return ccw_device_tm_start_key(cdev, tcw, intparm, lpm,
+                                      PAGE_DEFAULT_KEY);
+}
+EXPORT_SYMBOL(ccw_device_tm_start);
+
+/**
+ * ccw_device_tm_start_timeout - perform start function
+ * @cdev: ccw device on which to perform the start function
+ * @tcw: transport-command word to be started
+ * @intparm: user defined parameter to be passed to the interrupt handler
+ * @lpm: mask of paths to use
+ * @expires: time span in jiffies after which to abort request
+ *
+ * Start the tcw on the given ccw device. Return zero on success, non-zero
+ * otherwise.
+ */
+int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw,
+                              unsigned long intparm, u8 lpm, int expires)
+{
+       return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm,
+                                              PAGE_DEFAULT_KEY, expires);
+}
+EXPORT_SYMBOL(ccw_device_tm_start_timeout);
+
+/**
+ * ccw_device_tm_intrg - perform interrogate function
+ * @cdev: ccw device on which to perform the interrogate function
+ *
+ * Perform an interrogate function on the given ccw device. Return zero on
+ * success, non-zero otherwise.
+ */
+int ccw_device_tm_intrg(struct ccw_device *cdev)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               return -EIO;
+       if (!scsw_is_tm(&sch->schib.scsw) ||
+           !(scsw_actl(&sch->schib.scsw) | SCSW_ACTL_START_PEND))
+               return -EINVAL;
+       return cio_tm_intrg(sch);
+}
+EXPORT_SYMBOL(ccw_device_tm_intrg);
+
 // FIXME: these have to go:
 
 int
index 5cf7be008e981232742c7d57420e0359dd33e977..86bc94eb607f4b35f1094cd2148314f2e99932b2 100644 (file)
  * Helper function called from interrupt context to decide whether an
  * operation should be tried again.
  */
-static int __ccw_device_should_retry(struct scsw *scsw)
+static int __ccw_device_should_retry(union scsw *scsw)
 {
        /* CC is only valid if start function bit is set. */
-       if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1)
+       if ((scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && scsw->cmd.cc == 1)
                return 1;
        /* No more activity. For sense and set PGID we stubbornly try again. */
-       if (!scsw->actl)
+       if (!scsw->cmd.actl)
                return 1;
        return 0;
 }
@@ -125,7 +125,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
 
        sch = to_subchannel(cdev->dev.parent);
        irb = &cdev->private->irb;
-       if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
+       if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
                /* Retry Sense PGID if requested. */
                if (cdev->private->flags.intretry) {
                        cdev->private->flags.intretry = 0;
@@ -155,10 +155,10 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
                              irb->ecw[6], irb->ecw[7]);
                return -EAGAIN;
        }
-       if (irb->scsw.cc == 3) {
+       if (irb->scsw.cmd.cc == 3) {
                u8 lpm;
 
-               lpm = to_io_private(sch)->orb.lpm;
+               lpm = to_io_private(sch)->orb.cmd.lpm;
                CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x,"
                              " lpm %02X, became 'not operational'\n",
                              cdev->private->dev_id.devno, sch->schid.ssid,
@@ -188,7 +188,7 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
 
        irb = (struct irb *) __LC_IRB;
 
-       if (irb->scsw.stctl ==
+       if (irb->scsw.cmd.stctl ==
            (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
                if (__ccw_device_should_retry(&irb->scsw)) {
                        ret = __ccw_device_sense_pgid_start(cdev);
@@ -331,7 +331,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
 
        sch = to_subchannel(cdev->dev.parent);
        irb = &cdev->private->irb;
-       if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
+       if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
                /* Retry Set PGID if requested. */
                if (cdev->private->flags.intretry) {
                        cdev->private->flags.intretry = 0;
@@ -355,7 +355,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
                              irb->ecw[6], irb->ecw[7]);
                return -EAGAIN;
        }
-       if (irb->scsw.cc == 3) {
+       if (irb->scsw.cmd.cc == 3) {
                CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x,"
                              " lpm %02X, became 'not operational'\n",
                              cdev->private->dev_id.devno, sch->schid.ssid,
@@ -376,7 +376,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev)
 
        sch = to_subchannel(cdev->dev.parent);
        irb = &cdev->private->irb;
-       if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
+       if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
                /* Retry NOP if requested. */
                if (cdev->private->flags.intretry) {
                        cdev->private->flags.intretry = 0;
@@ -384,7 +384,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev)
                }
                return -ETIME;
        }
-       if (irb->scsw.cc == 3) {
+       if (irb->scsw.cmd.cc == 3) {
                CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x,"
                              " lpm %02X, became 'not operational'\n",
                              cdev->private->dev_id.devno, sch->schid.ssid,
@@ -438,7 +438,7 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
 
        irb = (struct irb *) __LC_IRB;
 
-       if (irb->scsw.stctl ==
+       if (irb->scsw.cmd.stctl ==
            (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
                if (__ccw_device_should_retry(&irb->scsw))
                        __ccw_device_verify_start(cdev);
@@ -544,7 +544,7 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
 
        irb = (struct irb *) __LC_IRB;
 
-       if (irb->scsw.stctl ==
+       if (irb->scsw.cmd.stctl ==
            (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
                if (__ccw_device_should_retry(&irb->scsw))
                        __ccw_device_disband_start(cdev);
index 4a38993000f2123d5e104af71ffa5ad0bcd2cd59..1b03c5423be207152d01786d41ccb1c799f8795d 100644 (file)
 static void
 ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
 {
-       if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
-                                SCHN_STAT_CHN_CTRL_CHK |
-                                SCHN_STAT_INTF_CTRL_CHK)))
+       char dbf_text[15];
+
+       if (!scsw_is_valid_cstat(&irb->scsw) ||
+           !(scsw_cstat(&irb->scsw) & (SCHN_STAT_CHN_DATA_CHK |
+             SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK)))
                return;
        CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
                      "received"
@@ -39,15 +41,10 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
                      ": %02X sch_stat : %02X\n",
                      cdev->private->dev_id.devno, cdev->private->schid.ssid,
                      cdev->private->schid.sch_no,
-                     irb->scsw.dstat, irb->scsw.cstat);
-
-       if (irb->scsw.cc != 3) {
-               char dbf_text[15];
-
-               sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no);
-               CIO_TRACE_EVENT(0, dbf_text);
-               CIO_HEX_EVENT(0, irb, sizeof (struct irb));
-       }
+                     scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw));
+       sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no);
+       CIO_TRACE_EVENT(0, dbf_text);
+       CIO_HEX_EVENT(0, irb, sizeof(struct irb));
 }
 
 /*
@@ -81,12 +78,12 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
         * are condition that have to be met for the extended control
         * bit to have meaning. Sick.
         */
-       cdev->private->irb.scsw.ectl = 0;
-       if ((irb->scsw.stctl & SCSW_STCTL_ALERT_STATUS) &&
-           !(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS))
-               cdev->private->irb.scsw.ectl = irb->scsw.ectl;
+       cdev->private->irb.scsw.cmd.ectl = 0;
+       if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) &&
+           !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS))
+               cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl;
        /* Check if extended control word is valid. */
-       if (!cdev->private->irb.scsw.ectl)
+       if (!cdev->private->irb.scsw.cmd.ectl)
                return;
        /* Copy concurrent sense / model dependent information. */
        memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw));
@@ -98,11 +95,12 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
 static int
 ccw_device_accumulate_esw_valid(struct irb *irb)
 {
-       if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
+       if (!irb->scsw.cmd.eswf &&
+           (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND))
                return 0;
-       if (irb->scsw.stctl == 
-                       (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
-           !(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
+       if (irb->scsw.cmd.stctl ==
+                       (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
+           !(irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
                return 0;
        return 1;
 }
@@ -125,7 +123,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
        cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum;
 
        /* Copy subchannel logout information if esw is of format 0. */
-       if (irb->scsw.eswf) {
+       if (irb->scsw.cmd.eswf) {
                cdev_sublog = &cdev_irb->esw.esw0.sublog;
                sublog = &irb->esw.esw0.sublog;
                /* Copy extended status flags. */
@@ -134,7 +132,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
                 * Copy fields that have a meaning for channel data check
                 * channel control check and interface control check.
                 */
-               if (irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
+               if (irb->scsw.cmd.cstat & (SCHN_STAT_CHN_DATA_CHK |
                                       SCHN_STAT_CHN_CTRL_CHK |
                                       SCHN_STAT_INTF_CTRL_CHK)) {
                        /* Copy ancillary report bit. */
@@ -155,7 +153,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
                /* Copy i/o-error alert. */
                cdev_sublog->ioerr = sublog->ioerr;
                /* Copy channel path timeout bit. */
-               if (irb->scsw.cstat & SCHN_STAT_INTF_CTRL_CHK)
+               if (irb->scsw.cmd.cstat & SCHN_STAT_INTF_CTRL_CHK)
                        cdev_irb->esw.esw0.erw.cpt = irb->esw.esw0.erw.cpt;
                /* Copy failing storage address validity flag. */
                cdev_irb->esw.esw0.erw.fsavf = irb->esw.esw0.erw.fsavf;
@@ -200,24 +198,24 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
         * If not, the remaining bit have no meaning and we must ignore them.
         * The esw is not meaningful as well...
         */
-       if (!(irb->scsw.stctl & SCSW_STCTL_STATUS_PEND))
+       if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))
                return;
 
        /* Check for channel checks and interface control checks. */
        ccw_device_msg_control_check(cdev, irb);
 
        /* Check for path not operational. */
-       if (irb->scsw.pno && irb->scsw.fctl != 0 &&
-           (!(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS) ||
-            (irb->scsw.actl & SCSW_ACTL_SUSPENDED)))
+       if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw))
                ccw_device_path_notoper(cdev);
-
+       /* No irb accumulation for transport mode irbs. */
+       if (scsw_is_tm(&irb->scsw)) {
+               memcpy(&cdev->private->irb, irb, sizeof(struct irb));
+               return;
+       }
        /*
         * Don't accumulate unsolicited interrupts.
         */
-       if ((irb->scsw.stctl ==
-            (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
-           (!irb->scsw.cc))
+       if (!scsw_is_solicited(&irb->scsw))
                return;
 
        cdev_irb = &cdev->private->irb;
@@ -227,62 +225,63 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
         * status at the subchannel has been cleared and we must not pass
         * intermediate accumulated status to the device driver.
         */
-       if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC)
+       if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC)
                memset(&cdev->private->irb, 0, sizeof(struct irb));
 
        /* Copy bits which are valid only for the start function. */
-       if (irb->scsw.fctl & SCSW_FCTL_START_FUNC) {
+       if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) {
                /* Copy key. */
-               cdev_irb->scsw.key = irb->scsw.key;
+               cdev_irb->scsw.cmd.key = irb->scsw.cmd.key;
                /* Copy suspend control bit. */
-               cdev_irb->scsw.sctl = irb->scsw.sctl;
+               cdev_irb->scsw.cmd.sctl = irb->scsw.cmd.sctl;
                /* Accumulate deferred condition code. */
-               cdev_irb->scsw.cc |= irb->scsw.cc;
+               cdev_irb->scsw.cmd.cc |= irb->scsw.cmd.cc;
                /* Copy ccw format bit. */
-               cdev_irb->scsw.fmt = irb->scsw.fmt;
+               cdev_irb->scsw.cmd.fmt = irb->scsw.cmd.fmt;
                /* Copy prefetch bit. */
-               cdev_irb->scsw.pfch = irb->scsw.pfch;
+               cdev_irb->scsw.cmd.pfch = irb->scsw.cmd.pfch;
                /* Copy initial-status-interruption-control. */
-               cdev_irb->scsw.isic = irb->scsw.isic;
+               cdev_irb->scsw.cmd.isic = irb->scsw.cmd.isic;
                /* Copy address limit checking control. */
-               cdev_irb->scsw.alcc = irb->scsw.alcc;
+               cdev_irb->scsw.cmd.alcc = irb->scsw.cmd.alcc;
                /* Copy suppress suspend bit. */
-               cdev_irb->scsw.ssi = irb->scsw.ssi;
+               cdev_irb->scsw.cmd.ssi = irb->scsw.cmd.ssi;
        }
 
        /* Take care of the extended control bit and extended control word. */
        ccw_device_accumulate_ecw(cdev, irb);
            
        /* Accumulate function control. */
-       cdev_irb->scsw.fctl |= irb->scsw.fctl;
+       cdev_irb->scsw.cmd.fctl |= irb->scsw.cmd.fctl;
        /* Copy activity control. */
-       cdev_irb->scsw.actl= irb->scsw.actl;
+       cdev_irb->scsw.cmd.actl = irb->scsw.cmd.actl;
        /* Accumulate status control. */
-       cdev_irb->scsw.stctl |= irb->scsw.stctl;
+       cdev_irb->scsw.cmd.stctl |= irb->scsw.cmd.stctl;
        /*
         * Copy ccw address if it is valid. This is a bit simplified
         * but should be close enough for all practical purposes.
         */
-       if ((irb->scsw.stctl & SCSW_STCTL_PRIM_STATUS) ||
-           ((irb->scsw.stctl == 
+       if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) ||
+           ((irb->scsw.cmd.stctl ==
              (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND)) &&
-            (irb->scsw.actl & SCSW_ACTL_DEVACT) &&
-            (irb->scsw.actl & SCSW_ACTL_SCHACT)) ||
-           (irb->scsw.actl & SCSW_ACTL_SUSPENDED))
-               cdev_irb->scsw.cpa = irb->scsw.cpa;
+            (irb->scsw.cmd.actl & SCSW_ACTL_DEVACT) &&
+            (irb->scsw.cmd.actl & SCSW_ACTL_SCHACT)) ||
+           (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
+               cdev_irb->scsw.cmd.cpa = irb->scsw.cmd.cpa;
        /* Accumulate device status, but not the device busy flag. */
-       cdev_irb->scsw.dstat &= ~DEV_STAT_BUSY;
+       cdev_irb->scsw.cmd.dstat &= ~DEV_STAT_BUSY;
        /* dstat is not always valid. */
-       if (irb->scsw.stctl &
+       if (irb->scsw.cmd.stctl &
            (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_SEC_STATUS
             | SCSW_STCTL_INTER_STATUS | SCSW_STCTL_ALERT_STATUS))
-               cdev_irb->scsw.dstat |= irb->scsw.dstat;
+               cdev_irb->scsw.cmd.dstat |= irb->scsw.cmd.dstat;
        /* Accumulate subchannel status. */
-       cdev_irb->scsw.cstat |= irb->scsw.cstat;
+       cdev_irb->scsw.cmd.cstat |= irb->scsw.cmd.cstat;
        /* Copy residual count if it is valid. */
-       if ((irb->scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
-           (irb->scsw.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN)) == 0)
-               cdev_irb->scsw.count = irb->scsw.count;
+       if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) &&
+           (irb->scsw.cmd.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN))
+            == 0)
+               cdev_irb->scsw.cmd.count = irb->scsw.cmd.count;
 
        /* Take care of bits in the extended status word. */
        ccw_device_accumulate_esw(cdev, irb);
@@ -299,7 +298,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
         *       sense facility available/supported when enabling the
         *       concurrent sense facility.
         */
-       if ((cdev_irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+       if ((cdev_irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
            !(cdev_irb->esw.esw0.erw.cons))
                cdev->private->flags.dosense = 1;
 }
@@ -317,7 +316,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
        sch = to_subchannel(cdev->dev.parent);
 
        /* A sense is required, can we do it now ? */
-       if ((irb->scsw.actl  & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
+       if (scsw_actl(&irb->scsw) & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT))
                /*
                 * we received an Unit Check but we have no final
                 *  status yet, therefore we must delay the SENSE
@@ -355,20 +354,18 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
         * If not, the remaining bit have no meaning and we must ignore them.
         * The esw is not meaningful as well...
         */
-       if (!(irb->scsw.stctl & SCSW_STCTL_STATUS_PEND))
+       if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))
                return;
 
        /* Check for channel checks and interface control checks. */
        ccw_device_msg_control_check(cdev, irb);
 
        /* Check for path not operational. */
-       if (irb->scsw.pno && irb->scsw.fctl != 0 &&
-           (!(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS) ||
-            (irb->scsw.actl & SCSW_ACTL_SUSPENDED)))
+       if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw))
                ccw_device_path_notoper(cdev);
 
-       if (!(irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
-           (irb->scsw.dstat & DEV_STAT_CHN_END)) {
+       if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
+           (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) {
                cdev->private->irb.esw.esw0.erw.cons = 1;
                cdev->private->flags.dosense = 0;
        }
@@ -386,11 +383,11 @@ int
 ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb)
 {
        ccw_device_accumulate_irb(cdev, irb);
-       if ((irb->scsw.actl  & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
+       if ((irb->scsw.cmd.actl  & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
                return -EBUSY;
        /* Check for basic sense. */
        if (cdev->private->flags.dosense &&
-           !(irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) {
+           !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) {
                cdev->private->irb.esw.esw0.erw.cons = 1;
                cdev->private->flags.dosense = 0;
                return 0;
diff --git a/drivers/s390/cio/fcx.c b/drivers/s390/cio/fcx.c
new file mode 100644 (file)
index 0000000..61677df
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ *  Functions for assembling fcx enabled I/O control blocks.
+ *
+ *    Copyright IBM Corp. 2008
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/fcx.h>
+#include "cio.h"
+
+/**
+ * tcw_get_intrg - return pointer to associated interrogate tcw
+ * @tcw: pointer to the original tcw
+ *
+ * Return a pointer to the interrogate tcw associated with the specified tcw
+ * or %NULL if there is no associated interrogate tcw.
+ */
+struct tcw *tcw_get_intrg(struct tcw *tcw)
+{
+       return (struct tcw *) ((addr_t) tcw->intrg);
+}
+EXPORT_SYMBOL(tcw_get_intrg);
+
+/**
+ * tcw_get_data - return pointer to input/output data associated with tcw
+ * @tcw: pointer to the tcw
+ *
+ * Return the input or output data address specified in the tcw depending
+ * on whether the r-bit or the w-bit is set. If neither bit is set, return
+ * %NULL.
+ */
+void *tcw_get_data(struct tcw *tcw)
+{
+       if (tcw->r)
+               return (void *) ((addr_t) tcw->input);
+       if (tcw->w)
+               return (void *) ((addr_t) tcw->output);
+       return NULL;
+}
+EXPORT_SYMBOL(tcw_get_data);
+
+/**
+ * tcw_get_tccb - return pointer to tccb associated with tcw
+ * @tcw: pointer to the tcw
+ *
+ * Return pointer to the tccb associated with this tcw.
+ */
+struct tccb *tcw_get_tccb(struct tcw *tcw)
+{
+       return (struct tccb *) ((addr_t) tcw->tccb);
+}
+EXPORT_SYMBOL(tcw_get_tccb);
+
+/**
+ * tcw_get_tsb - return pointer to tsb associated with tcw
+ * @tcw: pointer to the tcw
+ *
+ * Return pointer to the tsb associated with this tcw.
+ */
+struct tsb *tcw_get_tsb(struct tcw *tcw)
+{
+       return (struct tsb *) ((addr_t) tcw->tsb);
+}
+EXPORT_SYMBOL(tcw_get_tsb);
+
+/**
+ * tcw_init - initialize tcw data structure
+ * @tcw: pointer to the tcw to be initialized
+ * @r: initial value of the r-bit
+ * @w: initial value of the w-bit
+ *
+ * Initialize all fields of the specified tcw data structure with zero and
+ * fill in the format, flags, r and w fields.
+ */
+void tcw_init(struct tcw *tcw, int r, int w)
+{
+       memset(tcw, 0, sizeof(struct tcw));
+       tcw->format = TCW_FORMAT_DEFAULT;
+       tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT);
+       if (r)
+               tcw->r = 1;
+       if (w)
+               tcw->w = 1;
+}
+EXPORT_SYMBOL(tcw_init);
+
+static inline size_t tca_size(struct tccb *tccb)
+{
+       return tccb->tcah.tcal - 12;
+}
+
+static u32 calc_dcw_count(struct tccb *tccb)
+{
+       int offset;
+       struct dcw *dcw;
+       u32 count = 0;
+       size_t size;
+
+       size = tca_size(tccb);
+       for (offset = 0; offset < size;) {
+               dcw = (struct dcw *) &tccb->tca[offset];
+               count += dcw->count;
+               if (!(dcw->flags & DCW_FLAGS_CC))
+                       break;
+               offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4);
+       }
+       return count;
+}
+
+static u32 calc_cbc_size(struct tidaw *tidaw, int num)
+{
+       int i;
+       u32 cbc_data;
+       u32 cbc_count = 0;
+       u64 data_count = 0;
+
+       for (i = 0; i < num; i++) {
+               if (tidaw[i].flags & TIDAW_FLAGS_LAST)
+                       break;
+               /* TODO: find out if padding applies to total of data
+                * transferred or data transferred by this tidaw. Assumption:
+                * applies to total. */
+               data_count += tidaw[i].count;
+               if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) {
+                       cbc_data = 4 + ALIGN(data_count, 4) - data_count;
+                       cbc_count += cbc_data;
+                       data_count += cbc_data;
+               }
+       }
+       return cbc_count;
+}
+
+/**
+ * tcw_finalize - finalize tcw length fields and tidaw list
+ * @tcw: pointer to the tcw
+ * @num_tidaws: the number of tidaws used to address input/output data or zero
+ * if no tida is used
+ *
+ * Calculate the input-/output-count and tccbl field in the tcw, add a
+ * tcat the tccb and terminate the data tidaw list if used.
+ *
+ * Note: in case input- or output-tida is used, the tidaw-list must be stored
+ * in contiguous storage (no ttic). The tcal field in the tccb must be
+ * up-to-date.
+ */
+void tcw_finalize(struct tcw *tcw, int num_tidaws)
+{
+       struct tidaw *tidaw;
+       struct tccb *tccb;
+       struct tccb_tcat *tcat;
+       u32 count;
+
+       /* Terminate tidaw list. */
+       tidaw = tcw_get_data(tcw);
+       if (num_tidaws > 0)
+               tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST;
+       /* Add tcat to tccb. */
+       tccb = tcw_get_tccb(tcw);
+       tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)];
+       memset(tcat, 0, sizeof(tcat));
+       /* Calculate tcw input/output count and tcat transport count. */
+       count = calc_dcw_count(tccb);
+       if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA))
+               count += calc_cbc_size(tidaw, num_tidaws);
+       if (tcw->r)
+               tcw->input_count = count;
+       else if (tcw->w)
+               tcw->output_count = count;
+       tcat->count = ALIGN(count, 4) + 4;
+       /* Calculate tccbl. */
+       tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) +
+                     sizeof(struct tccb_tcat) - 20) >> 2;
+}
+EXPORT_SYMBOL(tcw_finalize);
+
+/**
+ * tcw_set_intrg - set the interrogate tcw address of a tcw
+ * @tcw: the tcw address
+ * @intrg_tcw: the address of the interrogate tcw
+ *
+ * Set the address of the interrogate tcw in the specified tcw.
+ */
+void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
+{
+       tcw->intrg = (u32) ((addr_t) intrg_tcw);
+}
+EXPORT_SYMBOL(tcw_set_intrg);
+
+/**
+ * tcw_set_data - set data address and tida flag of a tcw
+ * @tcw: the tcw address
+ * @data: the data address
+ * @use_tidal: zero of the data address specifies a contiguous block of data,
+ * non-zero if it specifies a list if tidaws.
+ *
+ * Set the input/output data address of a tcw (depending on the value of the
+ * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag
+ * is set as well.
+ */
+void tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
+{
+       if (tcw->r) {
+               tcw->input = (u64) ((addr_t) data);
+               if (use_tidal)
+                       tcw->flags |= TCW_FLAGS_INPUT_TIDA;
+       } else if (tcw->w) {
+               tcw->output = (u64) ((addr_t) data);
+               if (use_tidal)
+                       tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
+       }
+}
+EXPORT_SYMBOL(tcw_set_data);
+
+/**
+ * tcw_set_tccb - set tccb address of a tcw
+ * @tcw: the tcw address
+ * @tccb: the tccb address
+ *
+ * Set the address of the tccb in the specified tcw.
+ */
+void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
+{
+       tcw->tccb = (u64) ((addr_t) tccb);
+}
+EXPORT_SYMBOL(tcw_set_tccb);
+
+/**
+ * tcw_set_tsb - set tsb address of a tcw
+ * @tcw: the tcw address
+ * @tsb: the tsb address
+ *
+ * Set the address of the tsb in the specified tcw.
+ */
+void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
+{
+       tcw->tsb = (u64) ((addr_t) tsb);
+}
+EXPORT_SYMBOL(tcw_set_tsb);
+
+/**
+ * tccb_init - initialize tccb
+ * @tccb: the tccb address
+ * @size: the maximum size of the tccb
+ * @sac: the service-action-code to be user
+ *
+ * Initialize the header of the specified tccb by resetting all values to zero
+ * and filling in defaults for format, sac and initial tcal fields.
+ */
+void tccb_init(struct tccb *tccb, size_t size, u32 sac)
+{
+       memset(tccb, 0, size);
+       tccb->tcah.format = TCCB_FORMAT_DEFAULT;
+       tccb->tcah.sac = sac;
+       tccb->tcah.tcal = 12;
+}
+EXPORT_SYMBOL(tccb_init);
+
+/**
+ * tsb_init - initialize tsb
+ * @tsb: the tsb address
+ *
+ * Initialize the specified tsb by resetting all values to zero.
+ */
+void tsb_init(struct tsb *tsb)
+{
+       memset(tsb, 0, sizeof(tsb));
+}
+EXPORT_SYMBOL(tsb_init);
+
+/**
+ * tccb_add_dcw - add a dcw to the tccb
+ * @tccb: the tccb address
+ * @tccb_size: the maximum tccb size
+ * @cmd: the dcw command
+ * @flags: flags for the dcw
+ * @cd: pointer to control data for this dcw or NULL if none is required
+ * @cd_count: number of control data bytes for this dcw
+ * @count: number of data bytes for this dcw
+ *
+ * Add a new dcw to the specified tccb by writing the dcw information specified
+ * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return
+ * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw
+ * would exceed the available space as defined by @tccb_size.
+ *
+ * Note: the tcal field of the tccb header will be updates to reflect added
+ * content.
+ */
+struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags,
+                        void *cd, u8 cd_count, u32 count)
+{
+       struct dcw *dcw;
+       int size;
+       int tca_offset;
+
+       /* Check for space. */
+       tca_offset = tca_size(tccb);
+       size = ALIGN(sizeof(struct dcw) + cd_count, 4);
+       if (sizeof(struct tccb_tcah) + tca_offset + size +
+           sizeof(struct tccb_tcat) > tccb_size)
+               return ERR_PTR(-ENOSPC);
+       /* Add dcw to tca. */
+       dcw = (struct dcw *) &tccb->tca[tca_offset];
+       memset(dcw, 0, size);
+       dcw->cmd = cmd;
+       dcw->flags = flags;
+       dcw->count = count;
+       dcw->cd_count = cd_count;
+       if (cd)
+               memcpy(&dcw->cd[0], cd, cd_count);
+       tccb->tcah.tcal += size;
+       return dcw;
+}
+EXPORT_SYMBOL(tccb_add_dcw);
+
+/**
+ * tcw_add_tidaw - add a tidaw to a tcw
+ * @tcw: the tcw address
+ * @num_tidaws: the current number of tidaws
+ * @flags: flags for the new tidaw
+ * @addr: address value for the new tidaw
+ * @count: count value for the new tidaw
+ *
+ * Add a new tidaw to the input/output data tidaw-list of the specified tcw
+ * (depending on the value of the r-flag and w-flag) and return a pointer to
+ * the new tidaw.
+ *
+ * Note: the tidaw-list is assumed to be contiguous with no ttics. The caller
+ * must ensure that there is enough space for the new tidaw. The last-tidaw
+ * flag for the last tidaw in the list will be set by tcw_finalize.
+ */
+struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
+                           void *addr, u32 count)
+{
+       struct tidaw *tidaw;
+
+       /* Add tidaw to tidaw-list. */
+       tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws;
+       memset(tidaw, 0, sizeof(struct tidaw));
+       tidaw->flags = flags;
+       tidaw->count = count;
+       tidaw->addr = (u64) ((addr_t) addr);
+       return tidaw;
+}
+EXPORT_SYMBOL(tcw_add_tidaw);
index 144466ab8c15258e8f049e340c3e48d8dcdbebab..528065cb50212adc78c5c326197ee42d58e7351a 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef S390_IDSET_H
 #define S390_IDSET_H S390_IDSET_H
 
-#include "schid.h"
+#include <asm/schid.h>
 
 struct idset;
 
index 8c613160bfceb0e3b2ec905b95083eef55c14a76..3f8f1cf69c76d9082d3bad69d37d2a1dc0f5d123 100644 (file)
@@ -1,12 +1,12 @@
 #ifndef S390_IO_SCH_H
 #define S390_IO_SCH_H
 
-#include "schid.h"
+#include <asm/schid.h>
 
 /*
- * operation request block
+ * command-mode operation request block
  */
-struct orb {
+struct cmd_orb {
        u32 intparm;    /* interruption parameter */
        u32 key  : 4;   /* flags, like key, suspend control, etc. */
        u32 spnd : 1;   /* suspend control */
@@ -28,8 +28,36 @@ struct orb {
        u32 cpa;        /* channel program address */
 }  __attribute__ ((packed, aligned(4)));
 
+/*
+ * transport-mode operation request block
+ */
+struct tm_orb {
+       u32 intparm;
+       u32 key:4;
+       u32 :9;
+       u32 b:1;
+       u32 :2;
+       u32 lpm:8;
+       u32 :7;
+       u32 x:1;
+       u32 tcw;
+       u32 prio:8;
+       u32 :8;
+       u32 rsvpgm:8;
+       u32 :8;
+       u32 :32;
+       u32 :32;
+       u32 :32;
+       u32 :32;
+}  __attribute__ ((packed, aligned(4)));
+
+union orb {
+       struct cmd_orb cmd;
+       struct tm_orb tm;
+}  __attribute__ ((packed, aligned(4)));
+
 struct io_subchannel_private {
-       struct orb orb;         /* operation request block */
+       union orb orb;          /* operation request block */
        struct ccw1 sense_ccw;  /* static ccw for sense command */
 } __attribute__ ((aligned(8)));
 
@@ -95,16 +123,18 @@ struct ccw_device_private {
        void *cmb_wait;                 /* deferred cmb enable/disable */
 };
 
-static inline int ssch(struct subchannel_id schid, volatile struct orb *addr)
+static inline int ssch(struct subchannel_id schid, volatile union orb *addr)
 {
        register struct subchannel_id reg1 asm("1") = schid;
-       int ccode;
+       int ccode = -EIO;
 
        asm volatile(
                "       ssch    0(%2)\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "1:\n"
+               EX_TABLE(0b, 1b)
+               : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
        return ccode;
 }
 
index 652ea3625f9def33d92e8c4dde4ec50373adb091..9fa2ac13ac85cc94faf822f88f69d85072d57930 100644 (file)
@@ -2,7 +2,7 @@
 #define S390_CIO_IOASM_H
 
 #include <asm/chpid.h>
-#include "schid.h"
+#include <asm/schid.h>
 
 /*
  * TPI info structure
diff --git a/drivers/s390/cio/isc.c b/drivers/s390/cio/isc.c
new file mode 100644 (file)
index 0000000..c592087
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Functions for registration of I/O interruption subclasses on s390.
+ *
+ * Copyright IBM Corp. 2008
+ * Authors: Sebastian Ott <sebott@linux.vnet.ibm.com>
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/isc.h>
+
+static unsigned int isc_refs[MAX_ISC + 1];
+static DEFINE_SPINLOCK(isc_ref_lock);
+
+
+/**
+ * isc_register - register an I/O interruption subclass.
+ * @isc: I/O interruption subclass to register
+ *
+ * The number of users for @isc is increased. If this is the first user to
+ * register @isc, the corresponding I/O interruption subclass mask is enabled.
+ *
+ * Context:
+ *   This function must not be called in interrupt context.
+ */
+void isc_register(unsigned int isc)
+{
+       if (isc > MAX_ISC) {
+               WARN_ON(1);
+               return;
+       }
+
+       spin_lock(&isc_ref_lock);
+       if (isc_refs[isc] == 0)
+               ctl_set_bit(6, 31 - isc);
+       isc_refs[isc]++;
+       spin_unlock(&isc_ref_lock);
+}
+EXPORT_SYMBOL_GPL(isc_register);
+
+/**
+ * isc_unregister - unregister an I/O interruption subclass.
+ * @isc: I/O interruption subclass to unregister
+ *
+ * The number of users for @isc is decreased. If this is the last user to
+ * unregister @isc, the corresponding I/O interruption subclass mask is
+ * disabled.
+ * Note: This function must not be called if isc_register() hasn't been called
+ * before by the driver for @isc.
+ *
+ * Context:
+ *   This function must not be called in interrupt context.
+ */
+void isc_unregister(unsigned int isc)
+{
+       spin_lock(&isc_ref_lock);
+       /* check for misuse */
+       if (isc > MAX_ISC || isc_refs[isc] == 0) {
+               WARN_ON(1);
+               goto out_unlock;
+       }
+       if (isc_refs[isc] == 1)
+               ctl_clear_bit(6, 31 - isc);
+       isc_refs[isc]--;
+out_unlock:
+       spin_unlock(&isc_ref_lock);
+}
+EXPORT_SYMBOL_GPL(isc_unregister);
diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c
new file mode 100644 (file)
index 0000000..17da9ab
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ *  Functions for incremental construction of fcx enabled I/O control blocks.
+ *
+ *    Copyright IBM Corp. 2008
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <asm/fcx.h>
+#include <asm/itcw.h>
+
+/**
+ * struct itcw - incremental tcw helper data type
+ *
+ * This structure serves as a handle for the incremental construction of a
+ * tcw and associated tccb, tsb, data tidaw-list plus an optional interrogate
+ * tcw and associated data. The data structures are contained inside a single
+ * contiguous buffer provided by the user.
+ *
+ * The itcw construction functions take care of overall data integrity:
+ * - reset unused fields to zero
+ * - fill in required pointers
+ * - ensure required alignment for data structures
+ * - prevent data structures to cross 4k-byte boundary where required
+ * - calculate tccb-related length fields
+ * - optionally provide ready-made interrogate tcw and associated structures
+ *
+ * Restrictions apply to the itcws created with these construction functions:
+ * - tida only supported for data address, not for tccb
+ * - only contiguous tidaw-lists (no ttic)
+ * - total number of bytes required per itcw may not exceed 4k bytes
+ * - either read or write operation (may not work with r=0 and w=0)
+ *
+ * Example:
+ * struct itcw *itcw;
+ * void *buffer;
+ * size_t size;
+ *
+ * size = itcw_calc_size(1, 2, 0);
+ * buffer = kmalloc(size, GFP_DMA);
+ * if (!buffer)
+ *     return -ENOMEM;
+ * itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0);
+ * if (IS_ERR(itcw))
+ *     return PTR_ER(itcw);
+ * itcw_add_dcw(itcw, 0x2, 0, NULL, 0, 72);
+ * itcw_add_tidaw(itcw, 0, 0x30000, 20);
+ * itcw_add_tidaw(itcw, 0, 0x40000, 52);
+ * itcw_finalize(itcw);
+ *
+ */
+struct itcw {
+       struct tcw *tcw;
+       struct tcw *intrg_tcw;
+       int num_tidaws;
+       int max_tidaws;
+       int intrg_num_tidaws;
+       int intrg_max_tidaws;
+};
+
+/**
+ * itcw_get_tcw - return pointer to tcw associated with the itcw
+ * @itcw: address of the itcw
+ *
+ * Return pointer to the tcw associated with the itcw.
+ */
+struct tcw *itcw_get_tcw(struct itcw *itcw)
+{
+       return itcw->tcw;
+}
+EXPORT_SYMBOL(itcw_get_tcw);
+
+/**
+ * itcw_calc_size - return the size of an itcw with the given parameters
+ * @intrg: if non-zero, add an interrogate tcw
+ * @max_tidaws: maximum number of tidaws to be used for data addressing or zero
+ * if no tida is to be used.
+ * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing
+ * by the interrogate tcw, if specified
+ *
+ * Calculate and return the number of bytes required to hold an itcw with the
+ * given parameters and assuming tccbs with maximum size.
+ *
+ * Note that the resulting size also contains bytes needed for alignment
+ * padding as well as padding to ensure that data structures don't cross a
+ * 4k-boundary where required.
+ */
+size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws)
+{
+       size_t len;
+
+       /* Main data. */
+       len = sizeof(struct itcw);
+       len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE +
+              /* TSB */ sizeof(struct tsb) +
+              /* TIDAL */ max_tidaws * sizeof(struct tidaw);
+       /* Interrogate data. */
+       if (intrg) {
+               len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE +
+                      /* TSB */ sizeof(struct tsb) +
+                      /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw);
+       }
+       /* Maximum required alignment padding. */
+       len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7;
+       /* Maximum padding for structures that may not cross 4k boundary. */
+       if ((max_tidaws > 0) || (intrg_max_tidaws > 0))
+               len += max(max_tidaws, intrg_max_tidaws) *
+                      sizeof(struct tidaw) - 1;
+       return len;
+}
+EXPORT_SYMBOL(itcw_calc_size);
+
+#define CROSS4K(x, l)  (((x) & ~4095) != ((x + l) & ~4095))
+
+static inline void *fit_chunk(addr_t *start, addr_t end, size_t len,
+                             int align, int check_4k)
+{
+       addr_t addr;
+
+       addr = ALIGN(*start, align);
+       if (check_4k && CROSS4K(addr, len)) {
+               addr = ALIGN(addr, 4096);
+               addr = ALIGN(addr, align);
+       }
+       if (addr + len > end)
+               return ERR_PTR(-ENOSPC);
+       *start = addr + len;
+       return (void *) addr;
+}
+
+/**
+ * itcw_init - initialize incremental tcw data structure
+ * @buffer: address of buffer to use for data structures
+ * @size: number of bytes in buffer
+ * @op: %ITCW_OP_READ for a read operation tcw, %ITCW_OP_WRITE for a write
+ * operation tcw
+ * @intrg: if non-zero, add and initialize an interrogate tcw
+ * @max_tidaws: maximum number of tidaws to be used for data addressing or zero
+ * if no tida is to be used.
+ * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing
+ * by the interrogate tcw, if specified
+ *
+ * Prepare the specified buffer to be used as an incremental tcw, i.e. a
+ * helper data structure that can be used to construct a valid tcw by
+ * successive calls to other helper functions. Note: the buffer needs to be
+ * located below the 2G address limit. The resulting tcw has the following
+ * restrictions:
+ *  - no tccb tidal
+ *  - input/output tidal is contiguous (no ttic)
+ *  - total data should not exceed 4k
+ *  - tcw specifies either read or write operation
+ *
+ * On success, return pointer to the resulting incremental tcw data structure,
+ * ERR_PTR otherwise.
+ */
+struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
+                      int max_tidaws, int intrg_max_tidaws)
+{
+       struct itcw *itcw;
+       void *chunk;
+       addr_t start;
+       addr_t end;
+
+       /* Check for 2G limit. */
+       start = (addr_t) buffer;
+       end = start + size;
+       if (end > (1 << 31))
+               return ERR_PTR(-EINVAL);
+       memset(buffer, 0, size);
+       /* ITCW. */
+       chunk = fit_chunk(&start, end, sizeof(struct itcw), 1, 0);
+       if (IS_ERR(chunk))
+               return chunk;
+       itcw = chunk;
+       itcw->max_tidaws = max_tidaws;
+       itcw->intrg_max_tidaws = intrg_max_tidaws;
+       /* Main TCW. */
+       chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0);
+       if (IS_ERR(chunk))
+               return chunk;
+       itcw->tcw = chunk;
+       tcw_init(itcw->tcw, (op == ITCW_OP_READ) ? 1 : 0,
+                (op == ITCW_OP_WRITE) ? 1 : 0);
+       /* Interrogate TCW. */
+       if (intrg) {
+               chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0);
+               if (IS_ERR(chunk))
+                       return chunk;
+               itcw->intrg_tcw = chunk;
+               tcw_init(itcw->intrg_tcw, 1, 0);
+               tcw_set_intrg(itcw->tcw, itcw->intrg_tcw);
+       }
+       /* Data TIDAL. */
+       if (max_tidaws > 0) {
+               chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
+                                 max_tidaws, 16, 1);
+               if (IS_ERR(chunk))
+                       return chunk;
+               tcw_set_data(itcw->tcw, chunk, 1);
+       }
+       /* Interrogate data TIDAL. */
+       if (intrg && (intrg_max_tidaws > 0)) {
+               chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
+                                 intrg_max_tidaws, 16, 1);
+               if (IS_ERR(chunk))
+                       return chunk;
+               tcw_set_data(itcw->intrg_tcw, chunk, 1);
+       }
+       /* TSB. */
+       chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0);
+       if (IS_ERR(chunk))
+               return chunk;
+       tsb_init(chunk);
+       tcw_set_tsb(itcw->tcw, chunk);
+       /* Interrogate TSB. */
+       if (intrg) {
+               chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0);
+               if (IS_ERR(chunk))
+                       return chunk;
+               tsb_init(chunk);
+               tcw_set_tsb(itcw->intrg_tcw, chunk);
+       }
+       /* TCCB. */
+       chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0);
+       if (IS_ERR(chunk))
+               return chunk;
+       tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_DEFAULT);
+       tcw_set_tccb(itcw->tcw, chunk);
+       /* Interrogate TCCB. */
+       if (intrg) {
+               chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0);
+               if (IS_ERR(chunk))
+                       return chunk;
+               tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_INTRG);
+               tcw_set_tccb(itcw->intrg_tcw, chunk);
+               tccb_add_dcw(chunk, TCCB_MAX_SIZE, DCW_CMD_INTRG, 0, NULL,
+                            sizeof(struct dcw_intrg_data), 0);
+               tcw_finalize(itcw->intrg_tcw, 0);
+       }
+       return itcw;
+}
+EXPORT_SYMBOL(itcw_init);
+
+/**
+ * itcw_add_dcw - add a dcw to the itcw
+ * @itcw: address of the itcw
+ * @cmd: the dcw command
+ * @flags: flags for the dcw
+ * @cd: address of control data for this dcw or NULL if none is required
+ * @cd_count: number of control data bytes for this dcw
+ * @count: number of data bytes for this dcw
+ *
+ * Add a new dcw to the specified itcw by writing the dcw information specified
+ * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return
+ * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw
+ * would exceed the available space.
+ *
+ * Note: the tcal field of the tccb header will be updated to reflect added
+ * content.
+ */
+struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd,
+                        u8 cd_count, u32 count)
+{
+       return tccb_add_dcw(tcw_get_tccb(itcw->tcw), TCCB_MAX_SIZE, cmd,
+                           flags, cd, cd_count, count);
+}
+EXPORT_SYMBOL(itcw_add_dcw);
+
+/**
+ * itcw_add_tidaw - add a tidaw to the itcw
+ * @itcw: address of the itcw
+ * @flags: flags for the new tidaw
+ * @addr: address value for the new tidaw
+ * @count: count value for the new tidaw
+ *
+ * Add a new tidaw to the input/output data tidaw-list of the specified itcw
+ * (depending on the value of the r-flag and w-flag). Return a pointer to
+ * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the
+ * available space.
+ *
+ * Note: the tidaw-list is assumed to be contiguous with no ttics. The
+ * last-tidaw flag for the last tidaw in the list will be set by itcw_finalize.
+ */
+struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count)
+{
+       if (itcw->num_tidaws >= itcw->max_tidaws)
+               return ERR_PTR(-ENOSPC);
+       return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count);
+}
+EXPORT_SYMBOL(itcw_add_tidaw);
+
+/**
+ * itcw_set_data - set data address and tida flag of the itcw
+ * @itcw: address of the itcw
+ * @addr: the data address
+ * @use_tidal: zero of the data address specifies a contiguous block of data,
+ * non-zero if it specifies a list if tidaws.
+ *
+ * Set the input/output data address of the itcw (depending on the value of the
+ * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag
+ * is set as well.
+ */
+void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal)
+{
+       tcw_set_data(itcw->tcw, addr, use_tidal);
+}
+EXPORT_SYMBOL(itcw_set_data);
+
+/**
+ * itcw_finalize - calculate length and count fields of the itcw
+ * @itcw: address of the itcw
+ *
+ * Calculate tcw input-/output-count and tccbl fields and add a tcat the tccb.
+ * In case input- or output-tida is used, the tidaw-list must be stored in
+ * continuous storage (no ttic). The tcal field in the tccb must be
+ * up-to-date.
+ */
+void itcw_finalize(struct itcw *itcw)
+{
+       tcw_finalize(itcw->tcw, itcw->num_tidaws);
+}
+EXPORT_SYMBOL(itcw_finalize);
index 445cf364e461f353cf8dee05b6d98a3eb15e756c..2bf36e14b10214d4457a98c5fff8de69db1a306c 100644 (file)
@@ -2082,7 +2082,6 @@ qdio_timeout_handler(struct ccw_device *cdev)
        default:
                BUG();
        }
-       ccw_device_set_timeout(cdev, 0);
        wake_up(&cdev->private->wait_q);
 }
 
@@ -2121,6 +2120,8 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                case -EIO:
                        QDIO_PRINT_ERR("i/o error on device %s\n",
                                       cdev->dev.bus_id);
+                       qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
+                       wake_up(&cdev->private->wait_q);
                        return;
                case -ETIMEDOUT:
                        qdio_timeout_handler(cdev);
@@ -2139,8 +2140,8 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        QDIO_DBF_TEXT4(0, trace, dbf_text);
 #endif /* CONFIG_QDIO_DEBUG */
 
-        cstat = irb->scsw.cstat;
-        dstat = irb->scsw.dstat;
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
 
        switch (irq_ptr->state) {
        case QDIO_IRQ_STATE_INACTIVE:
@@ -2353,9 +2354,6 @@ tiqdio_check_chsc_availability(void)
 {
        char dbf_text[15];
 
-       if (!css_characteristics_avail)
-               return -EIO;
-
        /* Check for bit 41. */
        if (!css_general_characteristics.aif) {
                QDIO_PRINT_WARN("Adapter interruption facility not " \
@@ -2667,12 +2665,12 @@ qdio_shutdown(struct ccw_device *cdev, int how)
                spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
        } else if (rc == 0) {
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP);
-               ccw_device_set_timeout(cdev, timeout);
                spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags);
 
-               wait_event(cdev->private->wait_q,
-                          irq_ptr->state == QDIO_IRQ_STATE_INACTIVE ||
-                          irq_ptr->state == QDIO_IRQ_STATE_ERR);
+               wait_event_interruptible_timeout(cdev->private->wait_q,
+                       irq_ptr->state == QDIO_IRQ_STATE_INACTIVE ||
+                       irq_ptr->state == QDIO_IRQ_STATE_ERR,
+                       timeout);
        } else {
                QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for "
                                "device %s\n", result, cdev->dev.bus_id);
@@ -2692,7 +2690,6 @@ qdio_shutdown(struct ccw_device *cdev, int how)
 
        /* Ignore errors. */
        qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
-       ccw_device_set_timeout(cdev, 0);
 out:
        up(&irq_ptr->setting_up_sema);
        return result;
@@ -2907,13 +2904,10 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat)
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
-       if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) {
-               ccw_device_set_timeout(cdev, 0);
+       if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat))
                return;
-       }
 
        qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED);
-       ccw_device_set_timeout(cdev, 0);
 }
 
 int
@@ -3196,8 +3190,6 @@ qdio_establish(struct qdio_initialize *init_data)
                                irq_ptr->schid.ssid, irq_ptr->schid.sch_no,
                                result, result2);
                result=result2;
-               if (result)
-                       ccw_device_set_timeout(cdev, 0);
        }
 
        spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags);
@@ -3279,7 +3271,6 @@ qdio_activate(struct ccw_device *cdev, int flags)
 
        spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags);
 
-       ccw_device_set_timeout(cdev, 0);
        ccw_device_set_options(cdev, CCWDEV_REPORT_ALL);
        result=ccw_device_start(cdev,&irq_ptr->ccw,QDIO_DOING_ACTIVATE,
                                0, DOIO_DENY_PREFETCH);
@@ -3722,7 +3713,8 @@ tiqdio_register_thinints(void)
        char dbf_text[20];
 
        tiqdio_ind =
-               s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL);
+               s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL,
+                                               TIQDIO_THININT_ISC);
        if (IS_ERR(tiqdio_ind)) {
                sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
                QDIO_DBF_TEXT0(0,setup,dbf_text);
@@ -3738,7 +3730,8 @@ static void
 tiqdio_unregister_thinints(void)
 {
        if (tiqdio_ind)
-               s390_unregister_adapter_interrupt(tiqdio_ind);
+               s390_unregister_adapter_interrupt(tiqdio_ind,
+                                                 TIQDIO_THININT_ISC);
 }
 
 static int
@@ -3899,6 +3892,7 @@ init_QDIO(void)
                                            qdio_mempool_alloc,
                                            qdio_mempool_free, NULL);
 
+       isc_register(QDIO_AIRQ_ISC);
        if (tiqdio_check_chsc_availability())
                QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n");
 
@@ -3911,6 +3905,7 @@ static void __exit
 cleanup_QDIO(void)
 {
        tiqdio_unregister_thinints();
+       isc_unregister(QDIO_AIRQ_ISC);
        qdio_remove_procfs_entry();
        qdio_release_qdio_memory();
        qdio_unregister_dbf_views();
index c3df6b2c38b76c2d2c99a3bb8528c0598cd44ecf..7656081a24d284b33bc893571412e466e21b9585 100644 (file)
@@ -2,8 +2,8 @@
 #define _CIO_QDIO_H
 
 #include <asm/page.h>
-
-#include "schid.h"
+#include <asm/isc.h>
+#include <asm/schid.h>
 
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_VERBOSE_LEVEL 9
@@ -26,7 +26,7 @@
  */
 #define IQDIO_FILL_LEVEL_TO_POLL 4
 
-#define TIQDIO_THININT_ISC 3
+#define TIQDIO_THININT_ISC QDIO_AIRQ_ISC
 #define TIQDIO_DELAY_TARGET 0
 #define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */
 #define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */
diff --git a/drivers/s390/cio/scsw.c b/drivers/s390/cio/scsw.c
new file mode 100644 (file)
index 0000000..f8da25a
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ *  Helper functions for scsw access.
+ *
+ *    Copyright IBM Corp. 2008
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <asm/cio.h>
+#include "css.h"
+#include "chsc.h"
+
+/**
+ * scsw_is_tm - check for transport mode scsw
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the specified scsw is a transport mode scsw, zero
+ * otherwise.
+ */
+int scsw_is_tm(union scsw *scsw)
+{
+       return css_general_characteristics.fcx && (scsw->tm.x == 1);
+}
+EXPORT_SYMBOL(scsw_is_tm);
+
+/**
+ * scsw_key - return scsw key field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the key field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_key(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.key;
+       else
+               return scsw->cmd.key;
+}
+EXPORT_SYMBOL(scsw_key);
+
+/**
+ * scsw_eswf - return scsw eswf field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the eswf field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_eswf(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.eswf;
+       else
+               return scsw->cmd.eswf;
+}
+EXPORT_SYMBOL(scsw_eswf);
+
+/**
+ * scsw_cc - return scsw cc field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the cc field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_cc(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.cc;
+       else
+               return scsw->cmd.cc;
+}
+EXPORT_SYMBOL(scsw_cc);
+
+/**
+ * scsw_ectl - return scsw ectl field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the ectl field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_ectl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.ectl;
+       else
+               return scsw->cmd.ectl;
+}
+EXPORT_SYMBOL(scsw_ectl);
+
+/**
+ * scsw_pno - return scsw pno field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the pno field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_pno(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.pno;
+       else
+               return scsw->cmd.pno;
+}
+EXPORT_SYMBOL(scsw_pno);
+
+/**
+ * scsw_fctl - return scsw fctl field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the fctl field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_fctl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.fctl;
+       else
+               return scsw->cmd.fctl;
+}
+EXPORT_SYMBOL(scsw_fctl);
+
+/**
+ * scsw_actl - return scsw actl field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the actl field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_actl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.actl;
+       else
+               return scsw->cmd.actl;
+}
+EXPORT_SYMBOL(scsw_actl);
+
+/**
+ * scsw_stctl - return scsw stctl field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the stctl field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_stctl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.stctl;
+       else
+               return scsw->cmd.stctl;
+}
+EXPORT_SYMBOL(scsw_stctl);
+
+/**
+ * scsw_dstat - return scsw dstat field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the dstat field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_dstat(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.dstat;
+       else
+               return scsw->cmd.dstat;
+}
+EXPORT_SYMBOL(scsw_dstat);
+
+/**
+ * scsw_cstat - return scsw cstat field
+ * @scsw: pointer to scsw
+ *
+ * Return the value of the cstat field of the specified scsw, regardless of
+ * whether it is a transport mode or command mode scsw.
+ */
+u32 scsw_cstat(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw->tm.cstat;
+       else
+               return scsw->cmd.cstat;
+}
+EXPORT_SYMBOL(scsw_cstat);
+
+/**
+ * scsw_cmd_is_valid_key - check key field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the key field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_key(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_key);
+
+/**
+ * scsw_cmd_is_valid_sctl - check fctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fctl field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_sctl(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_sctl);
+
+/**
+ * scsw_cmd_is_valid_eswf - check eswf field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the eswf field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_eswf(union scsw *scsw)
+{
+       return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_eswf);
+
+/**
+ * scsw_cmd_is_valid_cc - check cc field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the cc field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_cc(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) &&
+              (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_cc);
+
+/**
+ * scsw_cmd_is_valid_fmt - check fmt field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fmt field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_fmt(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_fmt);
+
+/**
+ * scsw_cmd_is_valid_pfch - check pfch field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the pfch field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_pfch(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_pfch);
+
+/**
+ * scsw_cmd_is_valid_isic - check isic field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the isic field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_isic(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_isic);
+
+/**
+ * scsw_cmd_is_valid_alcc - check alcc field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the alcc field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_alcc(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_alcc);
+
+/**
+ * scsw_cmd_is_valid_ssi - check ssi field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the ssi field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_ssi(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_ssi);
+
+/**
+ * scsw_cmd_is_valid_zcc - check zcc field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the zcc field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_zcc(union scsw *scsw)
+{
+       return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) &&
+              (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_zcc);
+
+/**
+ * scsw_cmd_is_valid_ectl - check ectl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the ectl field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_ectl(union scsw *scsw)
+{
+       return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
+              !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) &&
+              (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_ectl);
+
+/**
+ * scsw_cmd_is_valid_pno - check pno field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the pno field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_pno(union scsw *scsw)
+{
+       return (scsw->cmd.fctl != 0) &&
+              (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
+              (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) ||
+                ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) &&
+                 (scsw->cmd.actl & SCSW_ACTL_SUSPENDED)));
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_pno);
+
+/**
+ * scsw_cmd_is_valid_fctl - check fctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fctl field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_fctl(union scsw *scsw)
+{
+       /* Only valid if pmcw.dnv == 1*/
+       return 1;
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_fctl);
+
+/**
+ * scsw_cmd_is_valid_actl - check actl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the actl field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_actl(union scsw *scsw)
+{
+       /* Only valid if pmcw.dnv == 1*/
+       return 1;
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_actl);
+
+/**
+ * scsw_cmd_is_valid_stctl - check stctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the stctl field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_stctl(union scsw *scsw)
+{
+       /* Only valid if pmcw.dnv == 1*/
+       return 1;
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_stctl);
+
+/**
+ * scsw_cmd_is_valid_dstat - check dstat field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the dstat field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_dstat(union scsw *scsw)
+{
+       return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
+              (scsw->cmd.cc != 3);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_dstat);
+
+/**
+ * scsw_cmd_is_valid_cstat - check cstat field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the cstat field of the specified command mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_cmd_is_valid_cstat(union scsw *scsw)
+{
+       return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) &&
+              (scsw->cmd.cc != 3);
+}
+EXPORT_SYMBOL(scsw_cmd_is_valid_cstat);
+
+/**
+ * scsw_tm_is_valid_key - check key field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the key field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_key(union scsw *scsw)
+{
+       return (scsw->tm.fctl & SCSW_FCTL_START_FUNC);
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_key);
+
+/**
+ * scsw_tm_is_valid_eswf - check eswf field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the eswf field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_eswf(union scsw *scsw)
+{
+       return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND);
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_eswf);
+
+/**
+ * scsw_tm_is_valid_cc - check cc field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the cc field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_cc(union scsw *scsw)
+{
+       return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) &&
+              (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND);
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_cc);
+
+/**
+ * scsw_tm_is_valid_fmt - check fmt field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fmt field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_fmt(union scsw *scsw)
+{
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_fmt);
+
+/**
+ * scsw_tm_is_valid_x - check x field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the x field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_x(union scsw *scsw)
+{
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_x);
+
+/**
+ * scsw_tm_is_valid_q - check q field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the q field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_q(union scsw *scsw)
+{
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_q);
+
+/**
+ * scsw_tm_is_valid_ectl - check ectl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the ectl field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_ectl(union scsw *scsw)
+{
+       return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
+              !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) &&
+              (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS);
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_ectl);
+
+/**
+ * scsw_tm_is_valid_pno - check pno field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the pno field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_pno(union scsw *scsw)
+{
+       return (scsw->tm.fctl != 0) &&
+              (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
+              (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) ||
+                ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) &&
+                 (scsw->tm.actl & SCSW_ACTL_SUSPENDED)));
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_pno);
+
+/**
+ * scsw_tm_is_valid_fctl - check fctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fctl field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_fctl(union scsw *scsw)
+{
+       /* Only valid if pmcw.dnv == 1*/
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_fctl);
+
+/**
+ * scsw_tm_is_valid_actl - check actl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the actl field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_actl(union scsw *scsw)
+{
+       /* Only valid if pmcw.dnv == 1*/
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_actl);
+
+/**
+ * scsw_tm_is_valid_stctl - check stctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the stctl field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_stctl(union scsw *scsw)
+{
+       /* Only valid if pmcw.dnv == 1*/
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_stctl);
+
+/**
+ * scsw_tm_is_valid_dstat - check dstat field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the dstat field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_dstat(union scsw *scsw)
+{
+       return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
+              (scsw->tm.cc != 3);
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_dstat);
+
+/**
+ * scsw_tm_is_valid_cstat - check cstat field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the cstat field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_cstat(union scsw *scsw)
+{
+       return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) &&
+              (scsw->tm.cc != 3);
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_cstat);
+
+/**
+ * scsw_tm_is_valid_fcxs - check fcxs field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fcxs field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_fcxs(union scsw *scsw)
+{
+       return 1;
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_fcxs);
+
+/**
+ * scsw_tm_is_valid_schxs - check schxs field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the schxs field of the specified transport mode scsw is
+ * valid, zero otherwise.
+ */
+int scsw_tm_is_valid_schxs(union scsw *scsw)
+{
+       return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK |
+                                 SCHN_STAT_INTF_CTRL_CHK |
+                                 SCHN_STAT_PROT_CHECK |
+                                 SCHN_STAT_CHN_DATA_CHK));
+}
+EXPORT_SYMBOL(scsw_tm_is_valid_schxs);
+
+/**
+ * scsw_is_valid_actl - check actl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the actl field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_actl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_actl(scsw);
+       else
+               return scsw_cmd_is_valid_actl(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_actl);
+
+/**
+ * scsw_is_valid_cc - check cc field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the cc field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_cc(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_cc(scsw);
+       else
+               return scsw_cmd_is_valid_cc(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_cc);
+
+/**
+ * scsw_is_valid_cstat - check cstat field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the cstat field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_cstat(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_cstat(scsw);
+       else
+               return scsw_cmd_is_valid_cstat(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_cstat);
+
+/**
+ * scsw_is_valid_dstat - check dstat field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the dstat field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_dstat(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_dstat(scsw);
+       else
+               return scsw_cmd_is_valid_dstat(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_dstat);
+
+/**
+ * scsw_is_valid_ectl - check ectl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the ectl field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_ectl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_ectl(scsw);
+       else
+               return scsw_cmd_is_valid_ectl(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_ectl);
+
+/**
+ * scsw_is_valid_eswf - check eswf field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the eswf field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_eswf(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_eswf(scsw);
+       else
+               return scsw_cmd_is_valid_eswf(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_eswf);
+
+/**
+ * scsw_is_valid_fctl - check fctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the fctl field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_fctl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_fctl(scsw);
+       else
+               return scsw_cmd_is_valid_fctl(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_fctl);
+
+/**
+ * scsw_is_valid_key - check key field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the key field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_key(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_key(scsw);
+       else
+               return scsw_cmd_is_valid_key(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_key);
+
+/**
+ * scsw_is_valid_pno - check pno field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the pno field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_pno(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_pno(scsw);
+       else
+               return scsw_cmd_is_valid_pno(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_pno);
+
+/**
+ * scsw_is_valid_stctl - check stctl field validity
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the stctl field of the specified scsw is valid,
+ * regardless of whether it is a transport mode or command mode scsw.
+ * Return zero if the field does not contain a valid value.
+ */
+int scsw_is_valid_stctl(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_valid_stctl(scsw);
+       else
+               return scsw_cmd_is_valid_stctl(scsw);
+}
+EXPORT_SYMBOL(scsw_is_valid_stctl);
+
+/**
+ * scsw_cmd_is_solicited - check for solicited scsw
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the command mode scsw indicates that the associated
+ * status condition is solicited, zero if it is unsolicited.
+ */
+int scsw_cmd_is_solicited(union scsw *scsw)
+{
+       return (scsw->cmd.cc != 0) || (scsw->cmd.stctl !=
+               (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS));
+}
+EXPORT_SYMBOL(scsw_cmd_is_solicited);
+
+/**
+ * scsw_tm_is_solicited - check for solicited scsw
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the transport mode scsw indicates that the associated
+ * status condition is solicited, zero if it is unsolicited.
+ */
+int scsw_tm_is_solicited(union scsw *scsw)
+{
+       return (scsw->tm.cc != 0) || (scsw->tm.stctl !=
+               (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS));
+}
+EXPORT_SYMBOL(scsw_tm_is_solicited);
+
+/**
+ * scsw_is_solicited - check for solicited scsw
+ * @scsw: pointer to scsw
+ *
+ * Return non-zero if the transport or command mode scsw indicates that the
+ * associated status condition is solicited, zero if it is unsolicited.
+ */
+int scsw_is_solicited(union scsw *scsw)
+{
+       if (scsw_is_tm(scsw))
+               return scsw_tm_is_solicited(scsw);
+       else
+               return scsw_cmd_is_solicited(scsw);
+}
+EXPORT_SYMBOL(scsw_is_solicited);
index a1ab3e3efd11dae257e6c8c0b1fb13c5f9bec524..62b6b55230d0d4e509910df984de16364b8c99f9 100644 (file)
 #include <linux/mutex.h>
 #include <asm/s390_rdev.h>
 #include <asm/reset.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
 
 #include "ap_bus.h"
 
 /* Some prototypes. */
 static void ap_scan_bus(struct work_struct *);
 static void ap_poll_all(unsigned long);
-static void ap_poll_timeout(unsigned long);
+static enum hrtimer_restart ap_poll_timeout(struct hrtimer *);
 static int ap_poll_thread_start(void);
 static void ap_poll_thread_stop(void);
 static void ap_request_timeout(unsigned long);
@@ -80,12 +82,15 @@ static DECLARE_WORK(ap_config_work, ap_scan_bus);
 /*
  * Tasklet & timer for AP request polling.
  */
-static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0);
 static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
 static atomic_t ap_poll_requests = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
 static struct task_struct *ap_poll_kthread = NULL;
 static DEFINE_MUTEX(ap_poll_thread_mutex);
+static struct hrtimer ap_poll_timer;
+/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
+ * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
+static unsigned long long poll_timeout = 250000;
 
 /**
  * ap_intructions_available() - Test if AP instructions are available.
@@ -636,11 +641,39 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus,
 
 static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store);
 
+static ssize_t poll_timeout_show(struct bus_type *bus, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout);
+}
+
+static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
+                                 size_t count)
+{
+       unsigned long long time;
+       ktime_t hr_time;
+
+       /* 120 seconds = maximum poll interval */
+       if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000)
+               return -EINVAL;
+       poll_timeout = time;
+       hr_time = ktime_set(0, poll_timeout);
+
+       if (!hrtimer_is_queued(&ap_poll_timer) ||
+           !hrtimer_forward(&ap_poll_timer, ap_poll_timer.expires, hr_time)) {
+               ap_poll_timer.expires = hr_time;
+               hrtimer_start(&ap_poll_timer, hr_time, HRTIMER_MODE_ABS);
+       }
+       return count;
+}
+
+static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store);
+
 static struct bus_attribute *const ap_bus_attrs[] = {
        &bus_attr_ap_domain,
        &bus_attr_config_time,
        &bus_attr_poll_thread,
-       NULL
+       &bus_attr_poll_timeout,
+       NULL,
 };
 
 /**
@@ -895,9 +928,10 @@ ap_config_timeout(unsigned long ptr)
  */
 static inline void ap_schedule_poll_timer(void)
 {
-       if (timer_pending(&ap_poll_timer))
+       if (hrtimer_is_queued(&ap_poll_timer))
                return;
-       mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME);
+       hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout),
+                     HRTIMER_MODE_ABS);
 }
 
 /**
@@ -1115,13 +1149,14 @@ EXPORT_SYMBOL(ap_cancel_message);
 
 /**
  * ap_poll_timeout(): AP receive polling for finished AP requests.
- * @unused: Unused variable.
+ * @unused: Unused pointer.
  *
- * Schedules the AP tasklet.
+ * Schedules the AP tasklet using a high resolution timer.
  */
-static void ap_poll_timeout(unsigned long unused)
+static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused)
 {
        tasklet_schedule(&ap_tasklet);
+       return HRTIMER_NORESTART;
 }
 
 /**
@@ -1344,6 +1379,14 @@ int __init ap_module_init(void)
        ap_config_timer.expires = jiffies + ap_config_time * HZ;
        add_timer(&ap_config_timer);
 
+       /* Setup the high resultion poll timer.
+        * If we are running under z/VM adjust polling to z/VM polling rate.
+        */
+       if (MACHINE_IS_VM)
+               poll_timeout = 1500000;
+       hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       ap_poll_timer.function = ap_poll_timeout;
+
        /* Start the low priority AP bus poll thread. */
        if (ap_thread_flag) {
                rc = ap_poll_thread_start();
@@ -1355,7 +1398,7 @@ int __init ap_module_init(void)
 
 out_work:
        del_timer_sync(&ap_config_timer);
-       del_timer_sync(&ap_poll_timer);
+       hrtimer_cancel(&ap_poll_timer);
        destroy_workqueue(ap_work_queue);
 out_root:
        s390_root_dev_unregister(ap_root_device);
@@ -1386,7 +1429,7 @@ void ap_module_exit(void)
        ap_reset_domain();
        ap_poll_thread_stop();
        del_timer_sync(&ap_config_timer);
-       del_timer_sync(&ap_poll_timer);
+       hrtimer_cancel(&ap_poll_timer);
        destroy_workqueue(ap_work_queue);
        tasklet_kill(&ap_tasklet);
        s390_root_dev_unregister(ap_root_device);
index c1e1200c43fc7a211b68a10048207470e810aef4..446378b308fcf2ca6447816cfc2daab59c481536 100644 (file)
@@ -92,6 +92,8 @@ struct ap_queue_status {
 #define AP_DEVICE_TYPE_PCIXCC  5
 #define AP_DEVICE_TYPE_CEX2A   6
 #define AP_DEVICE_TYPE_CEX2C   7
+#define AP_DEVICE_TYPE_CEX2A2  8
+#define AP_DEVICE_TYPE_CEX2C2  9
 
 /*
  * AP reset flag states
index 4d36e805a2348b40995c76625986559f735c5978..8a4964f3584bf46eb3621463cdb260e73a97fcce 100644 (file)
@@ -1068,10 +1068,8 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer,
 
 #define LBUFSIZE 1200UL
        lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
-       if (!lbuf) {
-               PRINTK("kmalloc failed!\n");
+       if (!lbuf)
                return 0;
-       }
 
        local_count = min(LBUFSIZE - 1, count);
        if (copy_from_user(lbuf, buffer, local_count) != 0) {
@@ -1081,23 +1079,15 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer,
        lbuf[local_count] = '\0';
 
        ptr = strstr(lbuf, "Online devices");
-       if (!ptr) {
-               PRINTK("Unable to parse data (missing \"Online devices\")\n");
+       if (!ptr)
                goto out;
-       }
        ptr = strstr(ptr, "\n");
-       if (!ptr) {
-               PRINTK("Unable to parse data (missing newline "
-                      "after \"Online devices\")\n");
+       if (!ptr)
                goto out;
-       }
        ptr++;
 
-       if (strstr(ptr, "Waiting work element counts") == NULL) {
-               PRINTK("Unable to parse data (missing "
-                      "\"Waiting work element counts\")\n");
+       if (strstr(ptr, "Waiting work element counts") == NULL)
                goto out;
-       }
 
        for (j = 0; j < 64 && *ptr; ptr++) {
                /*
@@ -1197,16 +1187,12 @@ int __init zcrypt_api_init(void)
 
        /* Register the request sprayer. */
        rc = misc_register(&zcrypt_misc_device);
-       if (rc < 0) {
-               PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
-                       zcrypt_misc_device.minor, rc);
+       if (rc < 0)
                goto out;
-       }
 
        /* Set up the proc file system */
        zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL);
        if (!zcrypt_entry) {
-               PRINTK("Couldn't create z90crypt proc entry\n");
                rc = -ENOMEM;
                goto out_misc;
        }
index 5c6e222b2ac4201a55b2e4da9d748a23cb753372..1d1ec74dadb223701d6d7dacf180bf5a4754b2f2 100644 (file)
 #ifndef _ZCRYPT_API_H_
 #define _ZCRYPT_API_H_
 
-/**
- * Macro definitions
- *
- * PDEBUG debugs in the form "zcrypt: function_name -> message"
- *
- * PRINTK is like PDEBUG, except that it is always enabled
- * PRINTKN is like PRINTK, except that it does not include the function name
- * PRINTKW is like PRINTK, except that it uses KERN_WARNING
- * PRINTKC is like PRINTK, except that it uses KERN_CRIT
- */
-#define DEV_NAME       "zcrypt"
-
-#define PRINTK(fmt, args...) \
-       printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args)
-#define PRINTKN(fmt, args...) \
-       printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
-#define PRINTKW(fmt, args...) \
-       printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __func__ , ## args)
-#define PRINTKC(fmt, args...) \
-       printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __func__ , ## args)
-
-#ifdef ZCRYPT_DEBUG
-#define PDEBUG(fmt, args...) \
-       printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args)
-#else
-#define PDEBUG(fmt, args...) do {} while (0)
-#endif
-
 #include "ap_bus.h"
 #include <asm/zcrypt.h>
 
index 08657f604b8c7c392397d9ae8b5aa3f6a8c18e4b..54f4cbc3be9e44eae1d56902df6d68c5adc6c531 100644 (file)
@@ -49,6 +49,7 @@
 
 static struct ap_device_id zcrypt_cex2a_ids[] = {
        { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
+       { AP_DEVICE(AP_DEVICE_TYPE_CEX2A2) },
        { /* end of list */ },
 };
 
@@ -242,9 +243,6 @@ static int convert_response(struct zcrypt_device *zdev,
                return convert_type80(zdev, reply,
                                      outputdata, outputdatalength);
        default: /* Unknown response type, this should NEVER EVER happen */
-               PRINTK("Unrecognized Message Header: %08x%08x\n",
-                      *(unsigned int *) reply->message,
-                      *(unsigned int *) (reply->message+4));
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
index 3e27fe77d2074f6e5884efcf9655d1f672d44a45..03ba27f05f9203931a6b381bfd07ba1af3ddefa7 100644 (file)
@@ -92,10 +92,6 @@ static inline int convert_error(struct zcrypt_device *zdev,
 {
        struct error_hdr *ehdr = reply->message;
 
-       PRINTK("Hardware error : Type %02x Message Header: %08x%08x\n",
-              ehdr->type, *(unsigned int *) reply->message,
-              *(unsigned int *) (reply->message + 4));
-
        switch (ehdr->reply_code) {
        case REP82_ERROR_OPERAND_INVALID:
        case REP82_ERROR_OPERAND_SIZE:
@@ -123,8 +119,6 @@ static inline int convert_error(struct zcrypt_device *zdev,
                zdev->online = 0;
                return -EAGAIN;
        default:
-               PRINTKW("unknown type %02x reply code = %d\n",
-                       ehdr->type, ehdr->reply_code);
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
index 6e93b4751782c4806501df1c2ce00f9120abf5dd..12da4815ba8eea3ffa8fbdbf773661dbb5650697 100644 (file)
@@ -226,9 +226,6 @@ static int convert_response(struct zcrypt_device *zdev,
                return convert_type84(zdev, reply,
                                      outputdata, outputdatalength);
        default: /* Unknown response type, this should NEVER EVER happen */
-               PRINTK("Unrecognized Message Header: %08x%08x\n",
-                      *(unsigned int *) reply->message,
-                      *(unsigned int *) (reply->message+4));
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
index 17ea56ce1c1141731a33790d800ca6b0de487529..779952cb19fc85a101485461077d75448387d89c 100644 (file)
@@ -361,26 +361,18 @@ static int convert_type86(struct zcrypt_device *zdev,
        service_rc = le16_to_cpu(msg->cprb.ccp_rtcode);
        if (unlikely(service_rc != 0)) {
                service_rs = le16_to_cpu(msg->cprb.ccp_rscode);
-               if (service_rc == 8 && service_rs == 66) {
-                       PDEBUG("Bad block format on PCICC\n");
+               if (service_rc == 8 && service_rs == 66)
                        return -EINVAL;
-               }
-               if (service_rc == 8 && service_rs == 65) {
-                       PDEBUG("Probably an even modulus on PCICC\n");
+               if (service_rc == 8 && service_rs == 65)
                        return -EINVAL;
-               }
                if (service_rc == 8 && service_rs == 770) {
-                       PDEBUG("Invalid key length on PCICC\n");
                        zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
                        return -EAGAIN;
                }
                if (service_rc == 8 && service_rs == 783) {
-                       PDEBUG("Extended bitlengths not enabled on PCICC\n");
                        zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
                        return -EAGAIN;
                }
-               PRINTK("Unknown service rc/rs (PCICC): %d/%d\n",
-                      service_rc, service_rs);
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
@@ -434,9 +426,6 @@ static int convert_response(struct zcrypt_device *zdev,
                                              outputdata, outputdatalength);
                /* no break, incorrect cprb version is an unknown response */
        default: /* Unknown response type, this should NEVER EVER happen */
-               PRINTK("Unrecognized Message Header: %08x%08x\n",
-                      *(unsigned int *) reply->message,
-                      *(unsigned int *) (reply->message+4));
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
index 0bc9b3188e64964ab2b98049e8f8ff518f3209b6..d8ad36f8154032ae5fab9e4cd998a2752aded0fb 100644 (file)
@@ -72,6 +72,7 @@ struct response_type {
 static struct ap_device_id zcrypt_pcixcc_ids[] = {
        { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
        { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
+       { AP_DEVICE(AP_DEVICE_TYPE_CEX2C2) },
        { /* end of list */ },
 };
 
@@ -289,38 +290,19 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
        ap_msg->length = sizeof(struct type6_hdr) +
                CEIL4(xcRB->request_control_blk_length) +
                xcRB->request_data_length;
-       if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) {
-               PRINTK("Combined message is too large (%ld/%d/%d).\n",
-                   sizeof(struct type6_hdr),
-                   xcRB->request_control_blk_length,
-                   xcRB->request_data_length);
+       if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
                return -EFAULT;
-       }
-       if (CEIL4(xcRB->reply_control_blk_length) >
-           PCIXCC_MAX_XCRB_REPLY_SIZE) {
-               PDEBUG("Reply CPRB length is too large (%d).\n",
-                   xcRB->request_control_blk_length);
+       if (CEIL4(xcRB->reply_control_blk_length) > PCIXCC_MAX_XCRB_REPLY_SIZE)
                return -EFAULT;
-       }
-       if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) {
-               PDEBUG("Reply data block length is too large (%d).\n",
-                   xcRB->reply_data_length);
+       if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE)
                return -EFAULT;
-       }
        replylen = CEIL4(xcRB->reply_control_blk_length) +
                CEIL4(xcRB->reply_data_length) +
                sizeof(struct type86_fmt2_msg);
        if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
-               PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE"
-                      " (%d/%d/%d).\n",
-                      sizeof(struct type86_fmt2_msg),
-                      xcRB->reply_control_blk_length,
-                      xcRB->reply_data_length);
                xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
                        (sizeof(struct type86_fmt2_msg) +
                            CEIL4(xcRB->reply_data_length));
-               PDEBUG("Capping Reply CPRB length at %d\n",
-                      xcRB->reply_control_blk_length);
        }
 
        /* prepare type6 header */
@@ -339,11 +321,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
                    xcRB->request_control_blk_length))
                return -EFAULT;
        if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
-           xcRB->request_control_blk_length) {
-               PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len,
-                   xcRB->request_control_blk_length);
+           xcRB->request_control_blk_length)
                return -EFAULT;
-       }
        function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
        memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
 
@@ -471,29 +450,18 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
        service_rc = msg->cprbx.ccp_rtcode;
        if (unlikely(service_rc != 0)) {
                service_rs = msg->cprbx.ccp_rscode;
-               if (service_rc == 8 && service_rs == 66) {
-                       PDEBUG("Bad block format on PCIXCC/CEX2C\n");
+               if (service_rc == 8 && service_rs == 66)
                        return -EINVAL;
-               }
-               if (service_rc == 8 && service_rs == 65) {
-                       PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n");
+               if (service_rc == 8 && service_rs == 65)
                        return -EINVAL;
-               }
-               if (service_rc == 8 && service_rs == 770) {
-                       PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
+               if (service_rc == 8 && service_rs == 770)
                        return -EINVAL;
-               }
                if (service_rc == 8 && service_rs == 783) {
-                       PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
                        zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
                        return -EAGAIN;
                }
-               if (service_rc == 12 && service_rs == 769) {
-                       PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+               if (service_rc == 12 && service_rs == 769)
                        return -EINVAL;
-               }
-               PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
-                      service_rc, service_rs);
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
@@ -569,11 +537,8 @@ static int convert_type86_rng(struct zcrypt_device *zdev,
        } __attribute__((packed)) *msg = reply->message;
        char *data = reply->message;
 
-       if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) {
-               PDEBUG("RNG response error on PCIXCC/CEX2C rc=%hu/rs=%hu\n",
-                      rc, rs);
+       if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0)
                return -EINVAL;
-       }
        memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2);
        return msg->fmt2.count2;
 }
@@ -598,9 +563,6 @@ static int convert_response_ica(struct zcrypt_device *zdev,
                                                  outputdata, outputdatalength);
                /* no break, incorrect cprb version is an unknown response */
        default: /* Unknown response type, this should NEVER EVER happen */
-               PRINTK("Unrecognized Message Header: %08x%08x\n",
-                      *(unsigned int *) reply->message,
-                      *(unsigned int *) (reply->message+4));
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
@@ -627,9 +589,6 @@ static int convert_response_xcrb(struct zcrypt_device *zdev,
                        return convert_type86_xcrb(zdev, reply, xcRB);
                /* no break, incorrect cprb version is an unknown response */
        default: /* Unknown response type, this should NEVER EVER happen */
-               PRINTK("Unrecognized Message Header: %08x%08x\n",
-                      *(unsigned int *) reply->message,
-                      *(unsigned int *) (reply->message+4));
                xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
@@ -653,9 +612,6 @@ static int convert_response_rng(struct zcrypt_device *zdev,
                        return convert_type86_rng(zdev, reply, data);
                /* no break, incorrect cprb version is an unknown response */
        default: /* Unknown response type, this should NEVER EVER happen */
-               PRINTK("Unrecognized Message Header: %08x%08x\n",
-                      *(unsigned int *) reply->message,
-                      *(unsigned int *) (reply->message+4));
                zdev->online = 0;
                return -EAGAIN; /* repeat the request on a different device. */
        }
@@ -700,10 +656,7 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
                        memcpy(msg->message, reply->message, length);
                        break;
                default:
-                       PRINTK("Invalid internal response type: %i\n",
-                           resp_type->type);
-                       memcpy(msg->message, &error_reply,
-                           sizeof error_reply);
+                       memcpy(msg->message, &error_reply, sizeof error_reply);
                }
        } else
                memcpy(msg->message, reply->message, sizeof error_reply);
index 04a1d7bf678c0c0b19ca4f239655683cc2170ecf..c644669a75c283278f023697b91c54d44d0f63ec 100644 (file)
@@ -703,7 +703,8 @@ claw_irq_handler(struct ccw_device *cdev,
        if (!cdev->dev.driver_data) {
                 printk(KERN_WARNING "claw: unsolicited interrupt for device:"
                        "%s received c-%02x d-%02x\n",
-                        cdev->dev.bus_id,irb->scsw.cstat, irb->scsw.dstat);
+                      cdev->dev.bus_id, irb->scsw.cmd.cstat,
+                      irb->scsw.cmd.dstat);
 #ifdef FUNCTRACE
                 printk(KERN_INFO "claw: %s() "
                        "exit on line %d\n",__func__,__LINE__);
@@ -732,22 +733,23 @@ claw_irq_handler(struct ccw_device *cdev,
 #ifdef IOTRACE
         printk(KERN_INFO "%s: interrupt for device: %04x "
                "received c-%02x d-%02x state-%02x\n",
-                dev->name, p_ch->devno, irb->scsw.cstat,
-               irb->scsw.dstat, p_ch->claw_state);
+              dev->name, p_ch->devno, irb->scsw.cmd.cstat,
+              irb->scsw.cmd.dstat, p_ch->claw_state);
 #endif
 
        /* Copy interruption response block. */
        memcpy(p_ch->irb, irb, sizeof(struct irb));
 
         /* Check for good subchannel return code, otherwise error message */
-        if (irb->scsw.cstat  &&  !(irb->scsw.cstat & SCHN_STAT_PCI)) {
+       if (irb->scsw.cmd.cstat && !(irb->scsw.cmd.cstat & SCHN_STAT_PCI)) {
                 printk(KERN_INFO "%s: subchannel check for device: %04x -"
                        " Sch Stat %02x  Dev Stat %02x CPA - %04x\n",
                         dev->name, p_ch->devno,
-                       irb->scsw.cstat, irb->scsw.dstat,irb->scsw.cpa);
+                       irb->scsw.cmd.cstat, irb->scsw.cmd.dstat,
+                       irb->scsw.cmd.cpa);
 #ifdef IOTRACE
                dumpit((char *)irb,sizeof(struct irb));
-               dumpit((char *)(unsigned long)irb->scsw.cpa,
+               dumpit((char *)(unsigned long)irb->scsw.cmd.cpa,
                        sizeof(struct ccw1));
 #endif
 #ifdef FUNCTRACE
@@ -759,22 +761,24 @@ claw_irq_handler(struct ccw_device *cdev,
         }
 
         /* Check the reason-code of a unit check */
-        if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
                 ccw_check_unit_check(p_ch, irb->ecw[0]);
-        }
 
         /* State machine to bring the connection up, down and to restart */
-        p_ch->last_dstat = irb->scsw.dstat;
+       p_ch->last_dstat = irb->scsw.cmd.dstat;
 
         switch (p_ch->claw_state) {
                 case CLAW_STOP:/* HALT_IO by claw_release (halt sequence) */
 #ifdef DEBUGMSG
                         printk(KERN_INFO "%s: CLAW_STOP enter\n", dev->name);
 #endif
-                        if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
-                       (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
-                       (p_ch->irb->scsw.stctl ==
-                       (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+                       if (!((p_ch->irb->scsw.cmd.stctl &
+                              SCSW_STCTL_SEC_STATUS) ||
+                           (p_ch->irb->scsw.cmd.stctl ==
+                               SCSW_STCTL_STATUS_PEND) ||
+                           (p_ch->irb->scsw.cmd.stctl ==
+                               (SCSW_STCTL_ALERT_STATUS |
+                                SCSW_STCTL_STATUS_PEND)))) {
 #ifdef FUNCTRACE
                                 printk(KERN_INFO "%s:%s Exit on line %d\n",
                                        dev->name,__func__,__LINE__);
@@ -798,10 +802,13 @@ claw_irq_handler(struct ccw_device *cdev,
                         printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO\n",
                                dev->name);
 #endif
-                        if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
-                       (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
-                       (p_ch->irb->scsw.stctl ==
-                       (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+                       if (!((p_ch->irb->scsw.cmd.stctl &
+                              SCSW_STCTL_SEC_STATUS) ||
+                           (p_ch->irb->scsw.cmd.stctl ==
+                            SCSW_STCTL_STATUS_PEND) ||
+                           (p_ch->irb->scsw.cmd.stctl ==
+                            (SCSW_STCTL_ALERT_STATUS |
+                             SCSW_STCTL_STATUS_PEND)))) {
 #ifdef FUNCTRACE
                                printk(KERN_INFO "%s:%s Exit on line %d\n",
                                        dev->name,__func__,__LINE__);
@@ -828,8 +835,8 @@ claw_irq_handler(struct ccw_device *cdev,
                                        "interrupt for device:"
                                        "%s received c-%02x d-%02x\n",
                                        cdev->dev.bus_id,
-                                       irb->scsw.cstat,
-                                       irb->scsw.dstat);
+                                       irb->scsw.cmd.cstat,
+                                       irb->scsw.cmd.dstat);
                                return;
                                }
 #ifdef DEBUGMSG
@@ -844,7 +851,7 @@ claw_irq_handler(struct ccw_device *cdev,
                         return;
                 case CLAW_START_READ:
                        CLAW_DBF_TEXT(4,trace,"ReadIRQ");
-                        if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+                       if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
                                 clear_bit(0, (void *)&p_ch->IO_active);
                                 if ((p_ch->irb->ecw[0] & 0x41) == 0x41 ||
                                     (p_ch->irb->ecw[0] & 0x40) == 0x40 ||
@@ -863,8 +870,8 @@ claw_irq_handler(struct ccw_device *cdev,
                                        CLAW_DBF_TEXT(4,trace,"notrdy");
                                         return;
                         }
-                        if ((p_ch->irb->scsw.cstat & SCHN_STAT_PCI) &&
-                           (p_ch->irb->scsw.dstat==0)) {
+                       if ((p_ch->irb->scsw.cmd.cstat & SCHN_STAT_PCI) &&
+                           (p_ch->irb->scsw.cmd.dstat == 0)) {
                                 if (test_and_set_bit(CLAW_BH_ACTIVE,
                                        (void *)&p_ch->flag_a) == 0) {
                                        tasklet_schedule(&p_ch->tasklet);
@@ -879,10 +886,13 @@ claw_irq_handler(struct ccw_device *cdev,
                                CLAW_DBF_TEXT(4,trace,"PCI_read");
                                 return;
                         }
-                        if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
-                        (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
-                        (p_ch->irb->scsw.stctl ==
-                        (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+                       if (!((p_ch->irb->scsw.cmd.stctl &
+                              SCSW_STCTL_SEC_STATUS) ||
+                            (p_ch->irb->scsw.cmd.stctl ==
+                             SCSW_STCTL_STATUS_PEND) ||
+                            (p_ch->irb->scsw.cmd.stctl ==
+                             (SCSW_STCTL_ALERT_STATUS |
+                              SCSW_STCTL_STATUS_PEND)))) {
 #ifdef FUNCTRACE
                                printk(KERN_INFO "%s:%s Exit on line %d\n",
                                        dev->name,__func__,__LINE__);
@@ -911,7 +921,7 @@ claw_irq_handler(struct ccw_device *cdev,
                        CLAW_DBF_TEXT(4,trace,"RdIRQXit");
                         return;
                 case CLAW_START_WRITE:
-                        if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+                       if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
                                 printk(KERN_INFO "%s: Unit Check Occured in "
                                        "write channel\n",dev->name);
                                 clear_bit(0, (void *)&p_ch->IO_active);
@@ -934,16 +944,19 @@ claw_irq_handler(struct ccw_device *cdev,
                                CLAW_DBF_TEXT(4,trace,"rstrtwrt");
                                 return;
                         }
-                        if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) {
+                       if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) {
                                         clear_bit(0, (void *)&p_ch->IO_active);
                                         printk(KERN_INFO "%s: Unit Exception "
                                                "Occured in write channel\n",
                                                dev->name);
                         }
-                        if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
-                       (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
-                       (p_ch->irb->scsw.stctl ==
-                       (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) {
+                       if (!((p_ch->irb->scsw.cmd.stctl &
+                              SCSW_STCTL_SEC_STATUS) ||
+                            (p_ch->irb->scsw.cmd.stctl ==
+                             SCSW_STCTL_STATUS_PEND) ||
+                            (p_ch->irb->scsw.cmd.stctl ==
+                             (SCSW_STCTL_ALERT_STATUS |
+                              SCSW_STCTL_STATUS_PEND)))) {
 #ifdef FUNCTRACE
                                printk(KERN_INFO "%s:%s Exit on line %d\n",
                                        dev->name,__func__,__LINE__);
index 2a106f3a076d1af655f5d2e0678f6515a3b0edae..7e6bd387f4d889f628929bd3fe08d5d212abc082 100644 (file)
@@ -257,9 +257,9 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg)
        if (duration > ch->prof.tx_time)
                ch->prof.tx_time = duration;
 
-       if (ch->irb->scsw.count != 0)
+       if (ch->irb->scsw.cmd.count != 0)
                ctcm_pr_debug("%s: TX not complete, remaining %d bytes\n",
-                            dev->name, ch->irb->scsw.count);
+                            dev->name, ch->irb->scsw.cmd.count);
        fsm_deltimer(&ch->timer);
        while ((skb = skb_dequeue(&ch->io_queue))) {
                priv->stats.tx_packets++;
@@ -353,7 +353,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg)
        struct channel *ch = arg;
        struct net_device *dev = ch->netdev;
        struct ctcm_priv *priv = dev->priv;
-       int len = ch->max_bufsize - ch->irb->scsw.count;
+       int len = ch->max_bufsize - ch->irb->scsw.cmd.count;
        struct sk_buff *skb = ch->trans_skb;
        __u16 block_len = *((__u16 *)skb->data);
        int check_len;
@@ -1234,9 +1234,9 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
        if (duration > ch->prof.tx_time)
                ch->prof.tx_time = duration;
 
-       if (ch->irb->scsw.count != 0)
+       if (ch->irb->scsw.cmd.count != 0)
                ctcm_pr_debug("%s: TX not complete, remaining %d bytes\n",
-                               dev->name, ch->irb->scsw.count);
+                               dev->name, ch->irb->scsw.cmd.count);
        fsm_deltimer(&ch->timer);
        while ((skb = skb_dequeue(&ch->io_queue))) {
                priv->stats.tx_packets++;
@@ -1394,7 +1394,7 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg)
        struct sk_buff          *skb = ch->trans_skb;
        struct sk_buff          *new_skb;
        unsigned long   saveflags = 0;  /* avoids compiler warning */
-       int len = ch->max_bufsize - ch->irb->scsw.count;
+       int len = ch->max_bufsize - ch->irb->scsw.cmd.count;
 
        if (do_debug_data) {
                CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, "mpc_ch_rx %s cp:%i %s\n",
index d52843da4f558c5afe916cf5955e705e2cd514a4..6b13c1c1beb81daccb09cb42a9967267e704f0cc 100644 (file)
@@ -1236,8 +1236,8 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
        /* Check for unsolicited interrupts. */
        if (cgdev == NULL) {
                ctcm_pr_warn("ctcm: Got unsolicited irq: %s c-%02x d-%02x\n",
-                           cdev->dev.bus_id, irb->scsw.cstat,
-                           irb->scsw.dstat);
+                           cdev->dev.bus_id, irb->scsw.cmd.cstat,
+                           irb->scsw.cmd.dstat);
                return;
        }
 
@@ -1266,40 +1266,40 @@ static void ctcm_irq_handler(struct ccw_device *cdev,
                                "received c-%02x d-%02x\n",
                                dev->name,
                                ch->id,
-                               irb->scsw.cstat,
-                               irb->scsw.dstat);
+                               irb->scsw.cmd.cstat,
+                               irb->scsw.cmd.dstat);
 
        /* Copy interruption response block. */
        memcpy(ch->irb, irb, sizeof(struct irb));
 
        /* Check for good subchannel return code, otherwise error message */
-       if (irb->scsw.cstat) {
+       if (irb->scsw.cmd.cstat) {
                fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch);
                ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n",
-                           dev->name, ch->id, irb->scsw.cstat,
-                           irb->scsw.dstat);
+                           dev->name, ch->id, irb->scsw.cmd.cstat,
+                           irb->scsw.cmd.dstat);
                return;
        }
 
        /* Check the reason-code of a unit check */
-       if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
                ccw_unit_check(ch, irb->ecw[0]);
                return;
        }
-       if (irb->scsw.dstat & DEV_STAT_BUSY) {
-               if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+       if (irb->scsw.cmd.dstat & DEV_STAT_BUSY) {
+               if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION)
                        fsm_event(ch->fsm, CTC_EVENT_ATTNBUSY, ch);
                else
                        fsm_event(ch->fsm, CTC_EVENT_BUSY, ch);
                return;
        }
-       if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
+       if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
                fsm_event(ch->fsm, CTC_EVENT_ATTN, ch);
                return;
        }
-       if ((irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||
-           (irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||
-           (irb->scsw.stctl ==
+       if ((irb->scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS) ||
+           (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND) ||
+           (irb->scsw.cmd.stctl ==
             (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))
                fsm_event(ch->fsm, CTC_EVENT_FINSTAT, ch);
        else
index 8e7697305a4cd9ab6d871f1d569d6d1e9ef31b4b..f4a32375c037410d78935033aa047f1ccdb8b2e9 100644 (file)
@@ -36,7 +36,6 @@ const char *cu3088_type[] = {
        "CTC/A",
        "ESCON channel",
        "FICON channel",
-       "P390 LCS card",
        "OSA LCS card",
        "CLAW channel device",
        "unknown channel type",
@@ -49,7 +48,6 @@ static struct ccw_device_id cu3088_ids[] = {
        { CCW_DEVICE(0x3088, 0x08), .driver_info = channel_type_parallel },
        { CCW_DEVICE(0x3088, 0x1f), .driver_info = channel_type_escon },
        { CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon },
-       { CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 },
        { CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 },
        { CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw },
        { /* end of list */ }
index 1753661f702a196325968df22cffec4485743f5e..d8558a7105a59446c5624fa66b8de5d2c951ce14 100644 (file)
@@ -17,9 +17,6 @@ enum channel_types {
        /* Device is a FICON channel */
        channel_type_ficon,
 
-       /* Device is a P390 LCS card */
-       channel_type_p390,
-
        /* Device is a OSA2 card */
        channel_type_osa2,
 
index dd22f4b37037ebaa25e25c49bda17de8670dddd6..6de28385b3546c08cf2899cffab0f2a09ff61bda 100644 (file)
@@ -1327,8 +1327,8 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
        char *sense;
 
        sense = (char *) irb->ecw;
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
 
        if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
                     SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
@@ -1388,11 +1388,13 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        else
                channel = &card->write;
 
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
        LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id);
-       LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat);
-       LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl);
+       LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.cstat,
+                     irb->scsw.cmd.dstat);
+       LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.fctl,
+                     irb->scsw.cmd.actl);
 
        /* Check for channel and device errors presented */
        rc = lcs_get_problem(cdev, irb);
@@ -1410,11 +1412,11 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        }
        /* How far in the ccw chain have we processed? */
        if ((channel->state != LCS_CH_STATE_INIT) &&
-           (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
-               index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa)
+           (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC)) {
+               index = (struct ccw1 *) __va((addr_t) irb->scsw.cmd.cpa)
                        - channel->ccws;
-               if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) ||
-                   (irb->scsw.cstat & SCHN_STAT_PCI))
+               if ((irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED) ||
+                   (irb->scsw.cmd.cstat & SCHN_STAT_PCI))
                        /* Bloody io subsystem tells us lies about cpa... */
                        index = (index - 1) & (LCS_NUM_BUFFS - 1);
                while (channel->io_idx != index) {
@@ -1425,25 +1427,24 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                }
        }
 
-       if ((irb->scsw.dstat & DEV_STAT_DEV_END) ||
-           (irb->scsw.dstat & DEV_STAT_CHN_END) ||
-           (irb->scsw.dstat & DEV_STAT_UNIT_CHECK))
+       if ((irb->scsw.cmd.dstat & DEV_STAT_DEV_END) ||
+           (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) ||
+           (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK))
                /* Mark channel as stopped. */
                channel->state = LCS_CH_STATE_STOPPED;
-       else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED)
+       else if (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED)
                /* CCW execution stopped on a suspend bit. */
                channel->state = LCS_CH_STATE_SUSPENDED;
-       if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) {
-               if (irb->scsw.cc != 0) {
+       if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) {
+               if (irb->scsw.cmd.cc != 0) {
                        ccw_device_halt(channel->ccwdev, (addr_t) channel);
                        return;
                }
                /* The channel has been stopped by halt_IO. */
                channel->state = LCS_CH_STATE_HALTED;
        }
-       if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
+       if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC)
                channel->state = LCS_CH_STATE_CLEARED;
-       }
        /* Do the rest in the tasklet. */
        tasklet_schedule(&channel->irq_tasklet);
 }
@@ -1761,7 +1762,7 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
                                netif_carrier_off(card->dev);
                        break;
                default:
-                       PRINT_INFO("UNRECOGNIZED LGW COMMAND\n");
+                       LCS_DBF_TEXT(5, trace, "noLGWcmd");
                        break;
                }
        } else
@@ -2042,13 +2043,12 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
        LCS_DBF_TEXT(2, setup, "add_dev");
         card = lcs_alloc_card();
         if (!card) {
-                PRINT_ERR("Allocation of lcs card failed\n");
+               LCS_DBF_TEXT_(2, setup, "  rc%d", -ENOMEM);
                put_device(&ccwgdev->dev);
                 return -ENOMEM;
         }
        ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group);
        if (ret) {
-                PRINT_ERR("Creating attributes failed");
                lcs_free_card(card);
                put_device(&ccwgdev->dev);
                return ret;
@@ -2140,7 +2140,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
        default:
                LCS_DBF_TEXT(3, setup, "errinit");
                PRINT_ERR("LCS: Initialization failed\n");
-               PRINT_ERR("LCS: No device found!\n");
                goto out;
        }
        if (!dev)
@@ -2269,7 +2268,6 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
        if (!card)
                return;
 
-       PRINT_INFO("Removing lcs group device ....\n");
        LCS_DBF_TEXT(3, setup, "remdev");
        LCS_DBF_HEX(3, setup, &card, sizeof(void*));
        if (ccwgdev->state == CCWGROUP_ONLINE) {
index e4ba6a0372acb6360124839afe6e651c1a6cec87..9242b5acc66ba8f63e0344569a8e9cf5e6c478e5 100644 (file)
@@ -625,9 +625,6 @@ static void netiucv_unpack_skb(struct iucv_connection *conn,
                offset += header->next;
                header->next -= NETIUCV_HDRLEN;
                if (skb_tailroom(pskb) < header->next) {
-                       PRINT_WARN("%s: Illegal next field in iucv header: "
-                              "%d > %d\n",
-                              dev->name, header->next, skb_tailroom(pskb));
                        IUCV_DBF_TEXT_(data, 2, "Illegal next field: %d > %d\n",
                                header->next, skb_tailroom(pskb));
                        return;
@@ -636,8 +633,6 @@ static void netiucv_unpack_skb(struct iucv_connection *conn,
                skb_reset_mac_header(pskb);
                skb = dev_alloc_skb(pskb->len);
                if (!skb) {
-                       PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n",
-                              dev->name);
                        IUCV_DBF_TEXT(data, 2,
                                "Out of memory in netiucv_unpack_skb\n");
                        privptr->stats.rx_dropped++;
@@ -674,7 +669,6 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg)
 
        if (!conn->netdev) {
                iucv_message_reject(conn->path, msg);
-               PRINT_WARN("Received data for unlinked connection\n");
                IUCV_DBF_TEXT(data, 2,
                              "Received data for unlinked connection\n");
                return;
@@ -682,8 +676,6 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg)
        if (msg->length > conn->max_buffsize) {
                iucv_message_reject(conn->path, msg);
                privptr->stats.rx_dropped++;
-               PRINT_WARN("msglen %d > max_buffsize %d\n",
-                          msg->length, conn->max_buffsize);
                IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",
                               msg->length, conn->max_buffsize);
                return;
@@ -695,7 +687,6 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg)
                                  msg->length, NULL);
        if (rc || msg->length < 5) {
                privptr->stats.rx_errors++;
-               PRINT_WARN("iucv_receive returned %08x\n", rc);
                IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);
                return;
        }
@@ -778,7 +769,6 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
                fsm_newstate(fi, CONN_STATE_IDLE);
                if (privptr)
                        privptr->stats.tx_errors += txpackets;
-               PRINT_WARN("iucv_send returned %08x\n", rc);
                IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
        } else {
                if (privptr) {
@@ -806,8 +796,6 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
        path->flags = 0;
        rc = iucv_path_accept(path, &netiucv_handler, NULL, conn);
        if (rc) {
-               PRINT_WARN("%s: IUCV accept failed with error %d\n",
-                      netdev->name, rc);
                IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc);
                return;
        }
@@ -873,7 +861,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg)
        IUCV_DBF_TEXT(trace, 3, __func__);
 
        fsm_newstate(fi, CONN_STATE_STARTWAIT);
-       PRINT_DEBUG("%s('%s'): connecting ...\n",
+       IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n",
                    conn->netdev->name, conn->userid);
 
        /*
@@ -968,8 +956,8 @@ static void conn_action_inval(fsm_instance *fi, int event, void *arg)
        struct iucv_connection *conn = arg;
        struct net_device *netdev = conn->netdev;
 
-       PRINT_WARN("%s: Cannot connect without username\n", netdev->name);
-       IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");
+       IUCV_DBF_TEXT_(data, 2, "%s('%s'): conn_action_inval called\n",
+               netdev->name, conn->userid);
 }
 
 static const fsm_node conn_fsm[] = {
@@ -1077,9 +1065,6 @@ dev_action_connup(fsm_instance *fi, int event, void *arg)
                                "connection is up and running\n");
                        break;
                case DEV_STATE_STOPWAIT:
-                       PRINT_INFO(
-                              "%s: got connection UP event during shutdown!\n",
-                              dev->name);
                        IUCV_DBF_TEXT(data, 2,
                                "dev_action_connup: in DEV_STATE_STOPWAIT\n");
                        break;
@@ -1174,8 +1159,6 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
                        nskb = alloc_skb(skb->len + NETIUCV_HDRLEN +
                                         NETIUCV_HDRLEN, GFP_ATOMIC | GFP_DMA);
                        if (!nskb) {
-                               PRINT_WARN("%s: Could not allocate tx_skb\n",
-                                      conn->netdev->name);
                                IUCV_DBF_TEXT(data, 2, "alloc_skb failed\n");
                                rc = -ENOMEM;
                                return rc;
@@ -1223,7 +1206,6 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
                                skb_pull(skb, NETIUCV_HDRLEN);
                                skb_trim(skb, skb->len - NETIUCV_HDRLEN);
                        }
-                       PRINT_WARN("iucv_send returned %08x\n", rc);
                        IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
                } else {
                        if (copied)
@@ -1293,14 +1275,11 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
         * Some sanity checks ...
         */
        if (skb == NULL) {
-               PRINT_WARN("%s: NULL sk_buff passed\n", dev->name);
                IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n");
                privptr->stats.tx_dropped++;
                return 0;
        }
        if (skb_headroom(skb) < NETIUCV_HDRLEN) {
-               PRINT_WARN("%s: Got sk_buff with head room < %ld bytes\n",
-                      dev->name, NETIUCV_HDRLEN);
                IUCV_DBF_TEXT(data, 2,
                        "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n");
                dev_kfree_skb(skb);
@@ -1393,7 +1372,6 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr,
 
        IUCV_DBF_TEXT(trace, 3, __func__);
        if (count > 9) {
-               PRINT_WARN("netiucv: username too long (%d)!\n", (int) count);
                IUCV_DBF_TEXT_(setup, 2,
                               "%d is length of username\n", (int) count);
                return -EINVAL;
@@ -1409,7 +1387,6 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr,
                        /* trailing lf, grr */
                        break;
                }
-               PRINT_WARN("netiucv: Invalid char %c in username!\n", *p);
                IUCV_DBF_TEXT_(setup, 2,
                               "username: invalid character %c\n", *p);
                return -EINVAL;
@@ -1421,18 +1398,15 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr,
        if (memcmp(username, priv->conn->userid, 9) &&
            (ndev->flags & (IFF_UP | IFF_RUNNING))) {
                /* username changed while the interface is active. */
-               PRINT_WARN("netiucv: device %s active, connected to %s\n",
-                          dev->bus_id, priv->conn->userid);
-               PRINT_WARN("netiucv: user cannot be updated\n");
                IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
-               return -EBUSY;
+               return -EPERM;
        }
        read_lock_bh(&iucv_connection_rwlock);
        list_for_each_entry(cp, &iucv_connection_list, list) {
                if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) {
                        read_unlock_bh(&iucv_connection_rwlock);
-                       PRINT_WARN("netiucv: Connection to %s already "
-                                  "exists\n", username);
+                       IUCV_DBF_TEXT_(setup, 2, "user_write: Connection "
+                               "to %s already exists\n", username);
                        return -EEXIST;
                }
        }
@@ -1466,13 +1440,10 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
        bs1 = simple_strtoul(buf, &e, 0);
 
        if (e && (!isspace(*e))) {
-               PRINT_WARN("netiucv: Invalid character in buffer!\n");
                IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e);
                return -EINVAL;
        }
        if (bs1 > NETIUCV_BUFSIZE_MAX) {
-               PRINT_WARN("netiucv: Given buffer size %d too large.\n",
-                       bs1);
                IUCV_DBF_TEXT_(setup, 2,
                        "buffer_write: buffer size %d too large\n",
                        bs1);
@@ -1480,16 +1451,12 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
        }
        if ((ndev->flags & IFF_RUNNING) &&
            (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2))) {
-               PRINT_WARN("netiucv: Given buffer size %d too small.\n",
-                       bs1);
                IUCV_DBF_TEXT_(setup, 2,
                        "buffer_write: buffer size %d too small\n",
                        bs1);
                return -EINVAL;
        }
        if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN)) {
-               PRINT_WARN("netiucv: Given buffer size %d too small.\n",
-                       bs1);
                IUCV_DBF_TEXT_(setup, 2,
                        "buffer_write: buffer size %d too small\n",
                        bs1);
@@ -1963,7 +1930,6 @@ static ssize_t conn_write(struct device_driver *drv,
 
        IUCV_DBF_TEXT(trace, 3, __func__);
        if (count>9) {
-               PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);
                IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n");
                return -EINVAL;
        }
@@ -1976,7 +1942,6 @@ static ssize_t conn_write(struct device_driver *drv,
                if (*p == '\n')
                        /* trailing lf, grr */
                        break;
-               PRINT_WARN("netiucv: Invalid character in username!\n");
                IUCV_DBF_TEXT_(setup, 2,
                               "conn_write: invalid character %c\n", *p);
                return -EINVAL;
@@ -1989,8 +1954,8 @@ static ssize_t conn_write(struct device_driver *drv,
        list_for_each_entry(cp, &iucv_connection_list, list) {
                if (!strncmp(username, cp->userid, 9)) {
                        read_unlock_bh(&iucv_connection_rwlock);
-                       PRINT_WARN("netiucv: Connection to %s already "
-                                  "exists\n", username);
+                       IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection "
+                               "to %s already exists\n", username);
                        return -EEXIST;
                }
        }
@@ -1998,9 +1963,6 @@ static ssize_t conn_write(struct device_driver *drv,
 
        dev = netiucv_init_netdevice(username);
        if (!dev) {
-               PRINT_WARN("netiucv: Could not allocate network device "
-                          "structure for user '%s'\n",
-                          netiucv_printname(username));
                IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
                return -ENODEV;
        }
@@ -2020,15 +1982,12 @@ static ssize_t conn_write(struct device_driver *drv,
        if (rc)
                goto out_unreg;
 
-       PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
 
        return count;
 
 out_unreg:
        netiucv_unregister_device(priv->dev);
 out_free_ndev:
-       PRINT_WARN("netiucv: Could not register '%s'\n", dev->name);
-       IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n");
        netiucv_free_netdevice(dev);
        return rc;
 }
@@ -2073,14 +2032,13 @@ static ssize_t remove_write (struct device_driver *drv,
                         PRINT_WARN("netiucv: %s cannot be removed\n",
                                   ndev->name);
                        IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
-                        return -EBUSY;
+                       return -EPERM;
                 }
                 unregister_netdev(ndev);
                 netiucv_unregister_device(dev);
                 return count;
         }
        read_unlock_bh(&iucv_connection_rwlock);
-        PRINT_WARN("netiucv: net device %s unknown\n", name);
        IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
         return -EINVAL;
 }
@@ -2148,7 +2106,6 @@ static int __init netiucv_init(void)
        netiucv_driver.groups = netiucv_drv_attr_groups;
        rc = driver_register(&netiucv_driver);
        if (rc) {
-               PRINT_ERR("NETIUCV: failed to register driver.\n");
                IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
                goto out_iucv;
        }
index 9a71dae223e81d94343d1ae72b54636bca290e12..0ac54dc638c21280f09dacf6c6a6ce2405111452 100644 (file)
@@ -420,7 +420,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
                                QETH_DBF_TEXT(TRACE, 3, "urla");
                                break;
                        default:
-                               PRINT_WARN("Received data is IPA "
+                               QETH_DBF_MESSAGE(2, "Received data is IPA "
                                           "but not a reply!\n");
                                break;
                        }
@@ -735,8 +735,8 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
        char *sense;
 
        sense = (char *) irb->ecw;
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
 
        if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
                     SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
@@ -823,8 +823,8 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
 
        if (__qeth_check_irb_error(cdev, intparm, irb))
                return;
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
+       cstat = irb->scsw.cmd.cstat;
+       dstat = irb->scsw.cmd.dstat;
 
        card = CARD_FROM_CDEV(cdev);
        if (!card)
@@ -842,10 +842,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
        }
        atomic_set(&channel->irq_pending, 0);
 
-       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC))
+       if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC))
                channel->state = CH_STATE_STOPPED;
 
-       if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC))
+       if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC))
                channel->state = CH_STATE_HALTED;
 
        /*let's wake up immediately on data channel*/
@@ -4092,7 +4092,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 
        rc = qeth_determine_card_type(card);
        if (rc) {
-               PRINT_WARN("%s: not a valid card type\n", __func__);
                QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
                goto err_card;
        }
index 999552c83bbe144c7082d1b8a55929df333f3375..06deaee50f6d1ce00e72bc837d23d6f483be4e7e 100644 (file)
@@ -944,15 +944,8 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
        else
                rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP,
                                        addr->del_flags);
-       if (rc) {
+       if (rc)
                QETH_DBF_TEXT(TRACE, 2, "failed");
-               /* TODO: re-activate this warning as soon as we have a
-                * clean mirco code
-               qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
-               PRINT_WARN("Could not deregister IP address %s (rc=%x)\n",
-                          buf, rc);
-               */
-       }
 
        return rc;
 }
index 8735a415a116feba2fc8a2b14befd0a6bae86e22..164e090c2625b03b8218c1e90286ca4b04b4559e 100644 (file)
@@ -156,11 +156,8 @@ static int __init smsg_init(void)
        if (rc != 0)
                goto out;
        rc = iucv_register(&smsg_handler, 1);
-       if (rc) {
-               printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
-               rc = -EIO;      /* better errno ? */
+       if (rc)
                goto out_driver;
-       }
        smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
        if (!smsg_path) {
                rc = -ENOMEM;
@@ -168,11 +165,8 @@ static int __init smsg_init(void)
        }
        rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
                               NULL, NULL, NULL);
-       if (rc) {
-               printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
-               rc = -EIO;      /* better errno ? */
+       if (rc)
                goto out_free;
-       }
        cpcmd("SET SMSG IUCV", NULL, 0, NULL);
        return 0;
 
index 5bfbe76598303be074518a4597f83305202960a8..834e9ee7e934f0e3222d17d0e7e929db565a615d 100644 (file)
@@ -2,10 +2,10 @@
  *  drivers/s390/s390mach.c
  *   S/390 machine check handler
  *
- *  S390 version
- *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2000,2008
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *              Cornelia Huck <cornelia.huck@de.ibm.com>
  */
 
 #include <linux/init.h>
 #include <asm/etr.h>
 #include <asm/lowcore.h>
 #include <asm/cio.h>
-#include "cio/cio.h"
-#include "cio/chsc.h"
-#include "cio/css.h"
-#include "cio/chp.h"
 #include "s390mach.h"
 
 static struct semaphore m_sem;
@@ -36,13 +32,40 @@ s390_handle_damage(char *msg)
        for(;;);
 }
 
+static crw_handler_t crw_handlers[NR_RSCS];
+
+/**
+ * s390_register_crw_handler() - register a channel report word handler
+ * @rsc: reporting source code to handle
+ * @handler: handler to be registered
+ *
+ * Returns %0 on success and a negative error value otherwise.
+ */
+int s390_register_crw_handler(int rsc, crw_handler_t handler)
+{
+       if ((rsc < 0) || (rsc >= NR_RSCS))
+               return -EINVAL;
+       if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
+               return 0;
+       return -EBUSY;
+}
+
+/**
+ * s390_unregister_crw_handler() - unregister a channel report word handler
+ * @rsc: reporting source code to handle
+ */
+void s390_unregister_crw_handler(int rsc)
+{
+       if ((rsc < 0) || (rsc >= NR_RSCS))
+               return;
+       xchg(&crw_handlers[rsc], NULL);
+       synchronize_sched();
+}
+
 /*
  * Retrieve CRWs and call function to handle event.
- *
- * Note : we currently process CRWs for io and chsc subchannels only
  */
-static int
-s390_collect_crw_info(void *param)
+static int s390_collect_crw_info(void *param)
 {
        struct crw crw[2];
        int ccode;
@@ -84,57 +107,24 @@ repeat:
                       crw[chain].rsid);
                /* Check for overflows. */
                if (crw[chain].oflw) {
+                       int i;
+
                        pr_debug("%s: crw overflow detected!\n", __func__);
-                       css_schedule_eval_all();
+                       for (i = 0; i < NR_RSCS; i++) {
+                               if (crw_handlers[i])
+                                       crw_handlers[i](NULL, NULL, 1);
+                       }
                        chain = 0;
                        continue;
                }
-               switch (crw[chain].rsc) {
-               case CRW_RSC_SCH:
-                       if (crw[0].chn && !chain)
-                               break;
-                       pr_debug("source is subchannel %04X\n", crw[0].rsid);
-                       css_process_crw(crw[0].rsid, chain ? crw[1].rsid : 0);
-                       break;
-               case CRW_RSC_MONITOR:
-                       pr_debug("source is monitoring facility\n");
-                       break;
-               case CRW_RSC_CPATH:
-                       pr_debug("source is channel path %02X\n", crw[0].rsid);
-                       /*
-                        * Check for solicited machine checks. These are
-                        * created by reset channel path and need not be
-                        * reported to the common I/O layer.
-                        */
-                       if (crw[chain].slct) {
-                               pr_debug("solicited machine check for "
-                                        "channel path %02X\n", crw[0].rsid);
-                               break;
-                       }
-                       switch (crw[0].erc) {
-                       case CRW_ERC_IPARM: /* Path has come. */
-                               chp_process_crw(crw[0].rsid, 1);
-                               break;
-                       case CRW_ERC_PERRI: /* Path has gone. */
-                       case CRW_ERC_PERRN:
-                               chp_process_crw(crw[0].rsid, 0);
-                               break;
-                       default:
-                               pr_debug("Don't know how to handle erc=%x\n",
-                                        crw[0].erc);
-                       }
-                       break;
-               case CRW_RSC_CONFIG:
-                       pr_debug("source is configuration-alert facility\n");
-                       break;
-               case CRW_RSC_CSS:
-                       pr_debug("source is channel subsystem\n");
-                       chsc_process_crw();
-                       break;
-               default:
-                       pr_debug("unknown source\n");
-                       break;
+               if (crw[0].chn && !chain) {
+                       chain++;
+                       continue;
                }
+               if (crw_handlers[crw[chain].rsc])
+                       crw_handlers[crw[chain].rsc](&crw[0],
+                                                    chain ? &crw[1] : NULL,
+                                                    0);
                /* chain is always 0 or 1 here. */
                chain = crw[chain].chn ? chain + 1 : 0;
        }
@@ -468,6 +458,10 @@ s390_do_machine_check(struct pt_regs *regs)
                        etr_sync_check();
                if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
                        etr_switch_to_local();
+               if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC))
+                       stp_sync_check();
+               if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))
+                       stp_island_check();
        }
 
        if (mci->se)
index ca681f9b67fccb36b037a5beccd23e2cd4f7d73c..d39f8b697d271d00311cfac4847676ddb102dd9d 100644 (file)
@@ -72,6 +72,13 @@ struct crw {
        __u32 rsid    : 16;   /* reporting-source ID */
 } __attribute__ ((packed));
 
+typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
+
+extern int s390_register_crw_handler(int rsc, crw_handler_t handler);
+extern void s390_unregister_crw_handler(int rsc);
+
+#define NR_RSCS 16
+
 #define CRW_RSC_MONITOR  0x2  /* monitoring facility */
 #define CRW_RSC_SCH      0x3  /* subchannel */
 #define CRW_RSC_CPATH    0x4  /* channel path */
@@ -105,6 +112,9 @@ static inline int stcrw(struct crw *pcrw )
 #define ED_ETR_SYNC    12      /* External damage ETR sync check */
 #define ED_ETR_SWITCH  13      /* External damage ETR switch to local */
 
+#define ED_STP_SYNC    7       /* External damage STP sync check */
+#define ED_STP_ISLAND  6       /* External damage STP island check */
+
 struct pt_regs;
 
 void s390_handle_mcck(void);
index ea0edd1b2e76692ce520a56bbcc5d62666f75fff..fe694f0ee19a80a6bc2895d84970f9a8e7e264ad 100644 (file)
@@ -182,8 +182,9 @@ static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
                         int tablesize);
 static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
                           Sg_request * srp);
-static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
-                           int blocking, int read_only, Sg_request ** o_srp);
+static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
+                       const char __user *buf, size_t count, int blocking,
+                       int read_only, Sg_request **o_srp);
 static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
                           unsigned char *cmnd, int timeout, int blocking);
 static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
@@ -204,7 +205,6 @@ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static int sg_allow_access(unsigned char opcode, char dev_type);
 static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static Sg_device *sg_get_dev(int dev);
 #ifdef CONFIG_SCSI_PROC_FS
@@ -544,7 +544,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
                return -EFAULT;
        blocking = !(filp->f_flags & O_NONBLOCK);
        if (old_hdr.reply_len < 0)
-               return sg_new_write(sfp, buf, count, blocking, 0, NULL);
+               return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL);
        if (count < (SZ_SG_HEADER + 6))
                return -EIO;    /* The minimum scsi command length is 6 bytes. */
 
@@ -621,8 +621,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
 }
 
 static ssize_t
-sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
-            int blocking, int read_only, Sg_request ** o_srp)
+sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
+                size_t count, int blocking, int read_only,
+                Sg_request **o_srp)
 {
        int k;
        Sg_request *srp;
@@ -678,8 +679,7 @@ sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
                sg_remove_request(sfp, srp);
                return -EFAULT;
        }
-       if (read_only &&
-           (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
+       if (read_only && !blk_verify_command(file, cmnd)) {
                sg_remove_request(sfp, srp);
                return -EPERM;
        }
@@ -799,7 +799,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
                        if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
                                return -EFAULT;
                        result =
-                           sg_new_write(sfp, p, SZ_SG_IO_HDR,
+                           sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
                                         blocking, read_only, &srp);
                        if (result < 0)
                                return result;
@@ -1048,7 +1048,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
 
                        if (copy_from_user(&opcode, siocp->data, 1))
                                return -EFAULT;
-                       if (!sg_allow_access(opcode, sdp->device->type))
+                       if (!blk_verify_command(filp, &opcode))
                                return -EPERM;
                }
                return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
@@ -2502,30 +2502,6 @@ sg_page_free(struct page *page, int size)
        __free_pages(page, order);
 }
 
-#ifndef MAINTENANCE_IN_CMD
-#define MAINTENANCE_IN_CMD 0xa3
-#endif
-
-static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE,
-       INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
-       READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS,
-       SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD
-};
-
-static int
-sg_allow_access(unsigned char opcode, char dev_type)
-{
-       int k;
-
-       if (TYPE_SCANNER == dev_type)   /* TYPE_ROM maybe burner */
-               return 1;
-       for (k = 0; k < sizeof (allow_ops); ++k) {
-               if (opcode == allow_ops[k])
-                       return 1;
-       }
-       return 0;
-}
-
 #ifdef CONFIG_SCSI_PROC_FS
 static int
 sg_idr_max_id(int id, void *p, void *data)
index c82df8bd4d8931cc72d3654a74edde4e4c9dd75b..27f5bfd1def343e205c2710a587571650026410f 100644 (file)
@@ -673,24 +673,20 @@ fail:
 static void get_sectorsize(struct scsi_cd *cd)
 {
        unsigned char cmd[10];
-       unsigned char *buffer;
+       unsigned char buffer[8];
        int the_result, retries = 3;
        int sector_size;
        struct request_queue *queue;
 
-       buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
-       if (!buffer)
-               goto Enomem;
-
        do {
                cmd[0] = READ_CAPACITY;
                memset((void *) &cmd[1], 0, 9);
-               memset(buffer, 0, 8);
+               memset(buffer, 0, sizeof(buffer));
 
                /* Do the command and wait.. */
                the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE,
-                                             buffer, 8, NULL, SR_TIMEOUT,
-                                             MAX_RETRIES);
+                                             buffer, sizeof(buffer), NULL,
+                                             SR_TIMEOUT, MAX_RETRIES);
 
                retries--;
 
@@ -745,14 +741,8 @@ static void get_sectorsize(struct scsi_cd *cd)
 
        queue = cd->device->request_queue;
        blk_queue_hardsect_size(queue, sector_size);
-out:
-       kfree(buffer);
-       return;
 
-Enomem:
-       cd->capacity = 0x1fffff;
-       cd->device->sector_size = 2048; /* A guess, just in case */
-       goto out;
+       return;
 }
 
 static void get_capabilities(struct scsi_cd *cd)
index 42be8b01a40f33210541c0c6bd1528e0314e6678..6aeef22bd2039ea41fbfc2cc6062dbb4c03cd83e 100644 (file)
@@ -1439,14 +1439,29 @@ static struct uart_driver atmel_uart = {
 };
 
 #ifdef CONFIG_PM
+static bool atmel_serial_clk_will_stop(void)
+{
+#ifdef CONFIG_ARCH_AT91
+       return at91_suspend_entering_slow_clock();
+#else
+       return false;
+#endif
+}
+
 static int atmel_serial_suspend(struct platform_device *pdev,
                                pm_message_t state)
 {
        struct uart_port *port = platform_get_drvdata(pdev);
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
+       if (atmel_is_console_port(port) && console_suspend_enabled) {
+               /* Drain the TX shifter */
+               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+                       cpu_relax();
+       }
+
        if (device_may_wakeup(&pdev->dev)
-           && !at91_suspend_entering_slow_clock())
+           && !atmel_serial_clk_will_stop())
                enable_irq_wake(port->irq);
        else {
                uart_suspend_port(&atmel_uart, port);
index e0c5f96b273d150bbca242222b6aee9869d716ba..9b887ef64ff1c27c857602833211dd2b6b2d7716 100644 (file)
@@ -7,7 +7,7 @@ menu "Graphics support"
 
 source "drivers/char/agp/Kconfig"
 
-source "drivers/char/drm/Kconfig"
+source "drivers/gpu/drm/Kconfig"
 
 config VGASTATE
        tristate
index 4fb16240c04d2d377354e6d060c356770bde4cb9..f5252c2552fdd482731eef311f3f4ff14a70f03d 100644 (file)
@@ -21,8 +21,7 @@
 
 #include <asm/io.h>
 #include <asm/mtrr.h>
-
-#include <setup_arch.h>
+#include <asm/visws/sgivw.h>
 
 #define INCLUDE_TIMING_TABLE_DATA
 #define DBE_REG_BASE par->regs
index 619a6f8d65a22c20b36395fe4d4d1ba2d89c7729..47ed39b52f9c32162e5265404a5aacff9f9fbebe 100644 (file)
@@ -18,6 +18,7 @@
  * frame buffer.
  */
 
+#include <linux/console.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
@@ -42,37 +43,68 @@ struct xenfb_info {
        struct xenfb_page       *page;
        unsigned long           *mfns;
        int                     update_wanted; /* XENFB_TYPE_UPDATE wanted */
+       int                     feature_resize; /* XENFB_TYPE_RESIZE ok */
+       struct xenfb_resize     resize;         /* protected by resize_lock */
+       int                     resize_dpy;     /* ditto */
+       spinlock_t              resize_lock;
 
        struct xenbus_device    *xbdev;
 };
 
-static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
+#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)
 
+enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT };
+static int video[KPARAM_CNT] = { 2, XENFB_WIDTH, XENFB_HEIGHT };
+module_param_array(video, int, NULL, 0);
+MODULE_PARM_DESC(video,
+       "Video memory size in MB, width, height in pixels (default 2,800,600)");
+
+static void xenfb_make_preferred_console(void);
 static int xenfb_remove(struct xenbus_device *);
-static void xenfb_init_shared_page(struct xenfb_info *);
+static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);
 static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
 static void xenfb_disconnect_backend(struct xenfb_info *);
 
+static void xenfb_send_event(struct xenfb_info *info,
+                            union xenfb_out_event *event)
+{
+       u32 prod;
+
+       prod = info->page->out_prod;
+       /* caller ensures !xenfb_queue_full() */
+       mb();                   /* ensure ring space available */
+       XENFB_OUT_RING_REF(info->page, prod) = *event;
+       wmb();                  /* ensure ring contents visible */
+       info->page->out_prod = prod + 1;
+
+       notify_remote_via_irq(info->irq);
+}
+
 static void xenfb_do_update(struct xenfb_info *info,
                            int x, int y, int w, int h)
 {
        union xenfb_out_event event;
-       u32 prod;
 
+       memset(&event, 0, sizeof(event));
        event.type = XENFB_TYPE_UPDATE;
        event.update.x = x;
        event.update.y = y;
        event.update.width = w;
        event.update.height = h;
 
-       prod = info->page->out_prod;
        /* caller ensures !xenfb_queue_full() */
-       mb();                   /* ensure ring space available */
-       XENFB_OUT_RING_REF(info->page, prod) = event;
-       wmb();                  /* ensure ring contents visible */
-       info->page->out_prod = prod + 1;
+       xenfb_send_event(info, &event);
+}
 
-       notify_remote_via_irq(info->irq);
+static void xenfb_do_resize(struct xenfb_info *info)
+{
+       union xenfb_out_event event;
+
+       memset(&event, 0, sizeof(event));
+       event.resize = info->resize;
+
+       /* caller ensures !xenfb_queue_full() */
+       xenfb_send_event(info, &event);
 }
 
 static int xenfb_queue_full(struct xenfb_info *info)
@@ -84,12 +116,28 @@ static int xenfb_queue_full(struct xenfb_info *info)
        return prod - cons == XENFB_OUT_RING_LEN;
 }
 
+static void xenfb_handle_resize_dpy(struct xenfb_info *info)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->resize_lock, flags);
+       if (info->resize_dpy) {
+               if (!xenfb_queue_full(info)) {
+                       info->resize_dpy = 0;
+                       xenfb_do_resize(info);
+               }
+       }
+       spin_unlock_irqrestore(&info->resize_lock, flags);
+}
+
 static void xenfb_refresh(struct xenfb_info *info,
                          int x1, int y1, int w, int h)
 {
        unsigned long flags;
-       int y2 = y1 + h - 1;
        int x2 = x1 + w - 1;
+       int y2 = y1 + h - 1;
+
+       xenfb_handle_resize_dpy(info);
 
        if (!info->update_wanted)
                return;
@@ -222,6 +270,57 @@ static ssize_t xenfb_write(struct fb_info *p, const char __user *buf,
        return res;
 }
 
+static int
+xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct xenfb_info *xenfb_info;
+       int required_mem_len;
+
+       xenfb_info = info->par;
+
+       if (!xenfb_info->feature_resize) {
+               if (var->xres == video[KPARAM_WIDTH] &&
+                   var->yres == video[KPARAM_HEIGHT] &&
+                   var->bits_per_pixel == xenfb_info->page->depth) {
+                       return 0;
+               }
+               return -EINVAL;
+       }
+
+       /* Can't resize past initial width and height */
+       if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT])
+               return -EINVAL;
+
+       required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8;
+       if (var->bits_per_pixel == xenfb_info->page->depth &&
+           var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) &&
+           required_mem_len <= info->fix.smem_len) {
+               var->xres_virtual = var->xres;
+               var->yres_virtual = var->yres;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int xenfb_set_par(struct fb_info *info)
+{
+       struct xenfb_info *xenfb_info;
+       unsigned long flags;
+
+       xenfb_info = info->par;
+
+       spin_lock_irqsave(&xenfb_info->resize_lock, flags);
+       xenfb_info->resize.type = XENFB_TYPE_RESIZE;
+       xenfb_info->resize.width = info->var.xres;
+       xenfb_info->resize.height = info->var.yres;
+       xenfb_info->resize.stride = info->fix.line_length;
+       xenfb_info->resize.depth = info->var.bits_per_pixel;
+       xenfb_info->resize.offset = 0;
+       xenfb_info->resize_dpy = 1;
+       spin_unlock_irqrestore(&xenfb_info->resize_lock, flags);
+       return 0;
+}
+
 static struct fb_ops xenfb_fb_ops = {
        .owner          = THIS_MODULE,
        .fb_read        = fb_sys_read,
@@ -230,6 +329,8 @@ static struct fb_ops xenfb_fb_ops = {
        .fb_fillrect    = xenfb_fillrect,
        .fb_copyarea    = xenfb_copyarea,
        .fb_imageblit   = xenfb_imageblit,
+       .fb_check_var   = xenfb_check_var,
+       .fb_set_par     = xenfb_set_par,
 };
 
 static irqreturn_t xenfb_event_handler(int rq, void *dev_id)
@@ -258,6 +359,8 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
 {
        struct xenfb_info *info;
        struct fb_info *fb_info;
+       int fb_size;
+       int val;
        int ret;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -265,18 +368,35 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
                xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
                return -ENOMEM;
        }
+
+       /* Limit kernel param videoram amount to what is in xenstore */
+       if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) {
+               if (val < video[KPARAM_MEM])
+                       video[KPARAM_MEM] = val;
+       }
+
+       /* If requested res does not fit in available memory, use default */
+       fb_size = video[KPARAM_MEM] * 1024 * 1024;
+       if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8
+           > fb_size) {
+               video[KPARAM_WIDTH] = XENFB_WIDTH;
+               video[KPARAM_HEIGHT] = XENFB_HEIGHT;
+               fb_size = XENFB_DEFAULT_FB_LEN;
+       }
+
        dev->dev.driver_data = info;
        info->xbdev = dev;
        info->irq = -1;
        info->x1 = info->y1 = INT_MAX;
        spin_lock_init(&info->dirty_lock);
+       spin_lock_init(&info->resize_lock);
 
-       info->fb = vmalloc(xenfb_mem_len);
+       info->fb = vmalloc(fb_size);
        if (info->fb == NULL)
                goto error_nomem;
-       memset(info->fb, 0, xenfb_mem_len);
+       memset(info->fb, 0, fb_size);
 
-       info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
        info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
        if (!info->mfns)
@@ -287,8 +407,6 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        if (!info->page)
                goto error_nomem;
 
-       xenfb_init_shared_page(info);
-
        /* abusing framebuffer_alloc() to allocate pseudo_palette */
        fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
        if (fb_info == NULL)
@@ -301,9 +419,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        fb_info->screen_base = info->fb;
 
        fb_info->fbops = &xenfb_fb_ops;
-       fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
-       fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
-       fb_info->var.bits_per_pixel = info->page->depth;
+       fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH];
+       fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT];
+       fb_info->var.bits_per_pixel = XENFB_DEPTH;
 
        fb_info->var.red = (struct fb_bitfield){16, 8, 0};
        fb_info->var.green = (struct fb_bitfield){8, 8, 0};
@@ -315,9 +433,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        fb_info->var.vmode = FB_VMODE_NONINTERLACED;
 
        fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
-       fb_info->fix.line_length = info->page->line_length;
+       fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8;
        fb_info->fix.smem_start = 0;
-       fb_info->fix.smem_len = xenfb_mem_len;
+       fb_info->fix.smem_len = fb_size;
        strcpy(fb_info->fix.id, "xen");
        fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
        fb_info->fix.accel = FB_ACCEL_NONE;
@@ -334,6 +452,8 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        fb_info->fbdefio = &xenfb_defio;
        fb_deferred_io_init(fb_info);
 
+       xenfb_init_shared_page(info, fb_info);
+
        ret = register_framebuffer(fb_info);
        if (ret) {
                fb_deferred_io_cleanup(fb_info);
@@ -348,6 +468,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        if (ret < 0)
                goto error;
 
+       xenfb_make_preferred_console();
        return 0;
 
  error_nomem:
@@ -358,12 +479,34 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
        return ret;
 }
 
+static __devinit void
+xenfb_make_preferred_console(void)
+{
+       struct console *c;
+
+       if (console_set_on_cmdline)
+               return;
+
+       acquire_console_sem();
+       for (c = console_drivers; c; c = c->next) {
+               if (!strcmp(c->name, "tty") && c->index == 0)
+                       break;
+       }
+       release_console_sem();
+       if (c) {
+               unregister_console(c);
+               c->flags |= CON_CONSDEV;
+               c->flags &= ~CON_PRINTBUFFER; /* don't print again */
+               register_console(c);
+       }
+}
+
 static int xenfb_resume(struct xenbus_device *dev)
 {
        struct xenfb_info *info = dev->dev.driver_data;
 
        xenfb_disconnect_backend(info);
-       xenfb_init_shared_page(info);
+       xenfb_init_shared_page(info, info->fb_info);
        return xenfb_connect_backend(dev, info);
 }
 
@@ -391,20 +534,23 @@ static unsigned long vmalloc_to_mfn(void *address)
        return pfn_to_mfn(vmalloc_to_pfn(address));
 }
 
-static void xenfb_init_shared_page(struct xenfb_info *info)
+static void xenfb_init_shared_page(struct xenfb_info *info,
+                                  struct fb_info *fb_info)
 {
        int i;
+       int epd = PAGE_SIZE / sizeof(info->mfns[0]);
 
        for (i = 0; i < info->nr_pages; i++)
                info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
 
-       info->page->pd[0] = vmalloc_to_mfn(info->mfns);
-       info->page->pd[1] = 0;
-       info->page->width = XENFB_WIDTH;
-       info->page->height = XENFB_HEIGHT;
-       info->page->depth = XENFB_DEPTH;
-       info->page->line_length = (info->page->depth / 8) * info->page->width;
-       info->page->mem_length = xenfb_mem_len;
+       for (i = 0; i * epd < info->nr_pages; i++)
+               info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]);
+
+       info->page->width = fb_info->var.xres;
+       info->page->height = fb_info->var.yres;
+       info->page->depth = fb_info->var.bits_per_pixel;
+       info->page->line_length = fb_info->fix.line_length;
+       info->page->mem_length = fb_info->fix.smem_len;
        info->page->in_cons = info->page->in_prod = 0;
        info->page->out_cons = info->page->out_prod = 0;
 }
@@ -504,6 +650,11 @@ InitWait:
                        val = 0;
                if (val)
                        info->update_wanted = 1;
+
+               if (xenbus_scanf(XBT_NIL, dev->otherend,
+                                "feature-resize", "%d", &val) < 0)
+                       val = 0;
+               info->feature_resize = val;
                break;
 
        case XenbusStateClosing:
@@ -547,4 +698,6 @@ static void __exit xenfb_cleanup(void)
 module_init(xenfb_init);
 module_exit(xenfb_cleanup);
 
+MODULE_DESCRIPTION("Xen virtual framebuffer device frontend");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vfb");
index 37af04f1ffd90d98a6ed33d5f29166d9d3747487..363286c542906e8fde4e5fb6f87ac718938cf55e 100644 (file)
@@ -1,4 +1,4 @@
-obj-y  += grant-table.o features.o events.o
+obj-y  += grant-table.o features.o events.o manage.o
 obj-y  += xenbus/
 obj-$(CONFIG_XEN_XENCOMM)      += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)      += balloon.o
index ab25ba6cbbb9ccf9737a77739400e0b08b2016f5..591bc29b55f5acf0f8dbe97e360ddd279020e9b2 100644 (file)
@@ -225,7 +225,7 @@ static int increase_reservation(unsigned long nr_pages)
                page = balloon_next_page(page);
        }
 
-       reservation.extent_start = (unsigned long)frame_list;
+       set_xen_guest_handle(reservation.extent_start, frame_list);
        reservation.nr_extents   = nr_pages;
        rc = HYPERVISOR_memory_op(
                XENMEM_populate_physmap, &reservation);
@@ -321,7 +321,7 @@ static int decrease_reservation(unsigned long nr_pages)
                balloon_append(pfn_to_page(pfn));
        }
 
-       reservation.extent_start = (unsigned long)frame_list;
+       set_xen_guest_handle(reservation.extent_start, frame_list);
        reservation.nr_extents   = nr_pages;
        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
        BUG_ON(ret != nr_pages);
@@ -368,7 +368,7 @@ static void balloon_process(struct work_struct *work)
 }
 
 /* Resets the Xen limit, sets new target, and kicks off processing. */
-void balloon_set_new_target(unsigned long target)
+static void balloon_set_new_target(unsigned long target)
 {
        /* No need for lock. Not read-modify-write updates. */
        balloon_stats.hard_limit   = ~0UL;
@@ -483,7 +483,7 @@ static int dealloc_pte_fn(
                .extent_order = 0,
                .domid        = DOMID_SELF
        };
-       reservation.extent_start = (unsigned long)&mfn;
+       set_xen_guest_handle(reservation.extent_start, &mfn);
        set_pte_at(&init_mm, addr, pte, __pte_ma(0ull));
        set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
@@ -519,7 +519,7 @@ static struct page **alloc_empty_pages_and_pagevec(int nr_pages)
                                .extent_order = 0,
                                .domid        = DOMID_SELF
                        };
-                       reservation.extent_start = (unsigned long)&gmfn;
+                       set_xen_guest_handle(reservation.extent_start, &gmfn);
                        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
                                                   &reservation);
                        if (ret == 1)
index 76e5b7386af953d7a8ee7c1ff7b17ec28a0fe407..332dd63750a01d41342844bc3f72e25891c4eab4 100644 (file)
@@ -355,7 +355,7 @@ static void unbind_from_irq(unsigned int irq)
 
        spin_lock(&irq_mapping_update_lock);
 
-       if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
+       if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) {
                close.port = evtchn;
                if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
                        BUG();
@@ -375,7 +375,7 @@ static void unbind_from_irq(unsigned int irq)
                evtchn_to_irq[evtchn] = -1;
                irq_info[irq] = IRQ_UNBOUND;
 
-               dynamic_irq_init(irq);
+               dynamic_irq_cleanup(irq);
        }
 
        spin_unlock(&irq_mapping_update_lock);
@@ -557,6 +557,33 @@ out:
        put_cpu();
 }
 
+/* Rebind a new event channel to an existing irq. */
+void rebind_evtchn_irq(int evtchn, int irq)
+{
+       /* Make sure the irq is masked, since the new event channel
+          will also be masked. */
+       disable_irq(irq);
+
+       spin_lock(&irq_mapping_update_lock);
+
+       /* After resume the irq<->evtchn mappings are all cleared out */
+       BUG_ON(evtchn_to_irq[evtchn] != -1);
+       /* Expect irq to have been bound before,
+          so the bindcount should be non-0 */
+       BUG_ON(irq_bindcount[irq] == 0);
+
+       evtchn_to_irq[evtchn] = irq;
+       irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
+
+       spin_unlock(&irq_mapping_update_lock);
+
+       /* new event channels are always bound to cpu 0 */
+       irq_set_affinity(irq, cpumask_of_cpu(0));
+
+       /* Unmask the event channel. */
+       enable_irq(irq);
+}
+
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
 static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
 {
@@ -647,6 +674,89 @@ static int retrigger_dynirq(unsigned int irq)
        return ret;
 }
 
+static void restore_cpu_virqs(unsigned int cpu)
+{
+       struct evtchn_bind_virq bind_virq;
+       int virq, irq, evtchn;
+
+       for (virq = 0; virq < NR_VIRQS; virq++) {
+               if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
+                       continue;
+
+               BUG_ON(irq_info[irq].type != IRQT_VIRQ);
+               BUG_ON(irq_info[irq].index != virq);
+
+               /* Get a new binding from Xen. */
+               bind_virq.virq = virq;
+               bind_virq.vcpu = cpu;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+                                               &bind_virq) != 0)
+                       BUG();
+               evtchn = bind_virq.port;
+
+               /* Record the new mapping. */
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
+               bind_evtchn_to_cpu(evtchn, cpu);
+
+               /* Ready for use. */
+               unmask_evtchn(evtchn);
+       }
+}
+
+static void restore_cpu_ipis(unsigned int cpu)
+{
+       struct evtchn_bind_ipi bind_ipi;
+       int ipi, irq, evtchn;
+
+       for (ipi = 0; ipi < XEN_NR_IPIS; ipi++) {
+               if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1)
+                       continue;
+
+               BUG_ON(irq_info[irq].type != IRQT_IPI);
+               BUG_ON(irq_info[irq].index != ipi);
+
+               /* Get a new binding from Xen. */
+               bind_ipi.vcpu = cpu;
+               if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+                                               &bind_ipi) != 0)
+                       BUG();
+               evtchn = bind_ipi.port;
+
+               /* Record the new mapping. */
+               evtchn_to_irq[evtchn] = irq;
+               irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
+               bind_evtchn_to_cpu(evtchn, cpu);
+
+               /* Ready for use. */
+               unmask_evtchn(evtchn);
+
+       }
+}
+
+void xen_irq_resume(void)
+{
+       unsigned int cpu, irq, evtchn;
+
+       init_evtchn_cpu_bindings();
+
+       /* New event-channel space is not 'live' yet. */
+       for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
+               mask_evtchn(evtchn);
+
+       /* No IRQ <-> event-channel mappings. */
+       for (irq = 0; irq < NR_IRQS; irq++)
+               irq_info[irq].evtchn = 0; /* zap event-channel binding */
+
+       for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
+               evtchn_to_irq[evtchn] = -1;
+
+       for_each_possible_cpu(cpu) {
+               restore_cpu_virqs(cpu);
+               restore_cpu_ipis(cpu);
+       }
+}
+
 static struct irq_chip xen_dynamic_chip __read_mostly = {
        .name           = "xen-dyn",
        .mask           = disable_dynirq,
index 52b6b41b909de5a142fc5eee2c96255e900c6039..e9e11168616af7a014b3d51db4a9ccc35208bbf5 100644 (file)
@@ -471,14 +471,14 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
        return 0;
 }
 
-static int gnttab_resume(void)
+int gnttab_resume(void)
 {
        if (max_nr_grant_frames() < nr_grant_frames)
                return -ENOSYS;
        return gnttab_map(0, nr_grant_frames - 1);
 }
 
-static int gnttab_suspend(void)
+int gnttab_suspend(void)
 {
        arch_gnttab_unmap_shared(shared, nr_grant_frames);
        return 0;
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
new file mode 100644 (file)
index 0000000..5b546e3
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Handle extern requests for shutdown, reboot and sysrq
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/stop_machine.h>
+#include <linux/freezer.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/hvc-console.h>
+#include <xen/xen-ops.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/page.h>
+
+enum shutdown_state {
+       SHUTDOWN_INVALID = -1,
+       SHUTDOWN_POWEROFF = 0,
+       SHUTDOWN_SUSPEND = 2,
+       /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
+          report a crash, not be instructed to crash!
+          HALT is the same as POWEROFF, as far as we're concerned.  The tools use
+          the distinction when we return the reason code to them.  */
+        SHUTDOWN_HALT = 4,
+};
+
+/* Ignore multiple shutdown requests. */
+static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
+
+#ifdef CONFIG_PM_SLEEP
+static int xen_suspend(void *data)
+{
+       int *cancelled = data;
+       int err;
+
+       BUG_ON(!irqs_disabled());
+
+       load_cr3(swapper_pg_dir);
+
+       err = device_power_down(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
+                      err);
+               return err;
+       }
+
+       xen_mm_pin_all();
+       gnttab_suspend();
+       xen_pre_suspend();
+
+       /*
+        * This hypercall returns 1 if suspend was cancelled
+        * or the domain was merely checkpointed, and 0 if it
+        * is resuming in a new domain.
+        */
+       *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
+
+       xen_post_suspend(*cancelled);
+       gnttab_resume();
+       xen_mm_unpin_all();
+
+       device_power_up();
+
+       if (!*cancelled) {
+               xen_irq_resume();
+               xen_console_resume();
+       }
+
+       return 0;
+}
+
+static void do_suspend(void)
+{
+       int err;
+       int cancelled = 1;
+
+       shutting_down = SHUTDOWN_SUSPEND;
+
+#ifdef CONFIG_PREEMPT
+       /* If the kernel is preemptible, we need to freeze all the processes
+          to prevent them from being in the middle of a pagetable update
+          during suspend. */
+       err = freeze_processes();
+       if (err) {
+               printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
+               return;
+       }
+#endif
+
+       err = device_suspend(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
+               goto out;
+       }
+
+       printk("suspending xenbus...\n");
+       /* XXX use normal device tree? */
+       xenbus_suspend();
+
+       err = stop_machine_run(xen_suspend, &cancelled, 0);
+       if (err) {
+               printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
+               goto out;
+       }
+
+       if (!cancelled)
+               xenbus_resume();
+       else
+               xenbus_suspend_cancel();
+
+       device_resume();
+
+       /* Make sure timer events get retriggered on all CPUs */
+       clock_was_set();
+out:
+#ifdef CONFIG_PREEMPT
+       thaw_processes();
+#endif
+       shutting_down = SHUTDOWN_INVALID;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static void shutdown_handler(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
+{
+       char *str;
+       struct xenbus_transaction xbt;
+       int err;
+
+       if (shutting_down != SHUTDOWN_INVALID)
+               return;
+
+ again:
+       err = xenbus_transaction_start(&xbt);
+       if (err)
+               return;
+
+       str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
+       /* Ignore read errors and empty reads. */
+       if (XENBUS_IS_ERR_READ(str)) {
+               xenbus_transaction_end(xbt, 1);
+               return;
+       }
+
+       xenbus_write(xbt, "control", "shutdown", "");
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN) {
+               kfree(str);
+               goto again;
+       }
+
+       if (strcmp(str, "poweroff") == 0 ||
+           strcmp(str, "halt") == 0) {
+               shutting_down = SHUTDOWN_POWEROFF;
+               orderly_poweroff(false);
+       } else if (strcmp(str, "reboot") == 0) {
+               shutting_down = SHUTDOWN_POWEROFF; /* ? */
+               ctrl_alt_del();
+#ifdef CONFIG_PM_SLEEP
+       } else if (strcmp(str, "suspend") == 0) {
+               do_suspend();
+#endif
+       } else {
+               printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
+               shutting_down = SHUTDOWN_INVALID;
+       }
+
+       kfree(str);
+}
+
+static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
+                         unsigned int len)
+{
+       char sysrq_key = '\0';
+       struct xenbus_transaction xbt;
+       int err;
+
+ again:
+       err = xenbus_transaction_start(&xbt);
+       if (err)
+               return;
+       if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
+               printk(KERN_ERR "Unable to read sysrq code in "
+                      "control/sysrq\n");
+               xenbus_transaction_end(xbt, 1);
+               return;
+       }
+
+       if (sysrq_key != '\0')
+               xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+
+       if (sysrq_key != '\0')
+               handle_sysrq(sysrq_key, NULL);
+}
+
+static struct xenbus_watch shutdown_watch = {
+       .node = "control/shutdown",
+       .callback = shutdown_handler
+};
+
+static struct xenbus_watch sysrq_watch = {
+       .node = "control/sysrq",
+       .callback = sysrq_handler
+};
+
+static int setup_shutdown_watcher(void)
+{
+       int err;
+
+       err = register_xenbus_watch(&shutdown_watch);
+       if (err) {
+               printk(KERN_ERR "Failed to set shutdown watcher\n");
+               return err;
+       }
+
+       err = register_xenbus_watch(&sysrq_watch);
+       if (err) {
+               printk(KERN_ERR "Failed to set sysrq watcher\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int shutdown_event(struct notifier_block *notifier,
+                         unsigned long event,
+                         void *data)
+{
+       setup_shutdown_watcher();
+       return NOTIFY_DONE;
+}
+
+static int __init setup_shutdown_event(void)
+{
+       static struct notifier_block xenstore_notifier = {
+               .notifier_call = shutdown_event
+       };
+       register_xenstore_notifier(&xenstore_notifier);
+
+       return 0;
+}
+
+subsys_initcall(setup_shutdown_event);
index 0f86b0ff78796517838399d956e90577924f56e5..9678b3e98c635014bebc845d79552aadaacbc596 100644 (file)
@@ -117,7 +117,7 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev,
        char *path;
 
        va_start(ap, pathfmt);
-       path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+       path = kvasprintf(GFP_NOIO | __GFP_HIGH, pathfmt, ap);
        va_end(ap);
 
        if (!path) {
index 6efbe3f29ca5751954cddfb94e55a1652739b5fe..090c61ee8fd0a313bea9c50529b1013bde20d062 100644 (file)
@@ -203,7 +203,6 @@ int xb_read(void *data, unsigned len)
 int xb_init_comms(void)
 {
        struct xenstore_domain_interface *intf = xen_store_interface;
-       int err;
 
        if (intf->req_prod != intf->req_cons)
                printk(KERN_ERR "XENBUS request ring is not quiescent "
@@ -216,18 +215,20 @@ int xb_init_comms(void)
                intf->rsp_cons = intf->rsp_prod;
        }
 
-       if (xenbus_irq)
-               unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+       if (xenbus_irq) {
+               /* Already have an irq; assume we're resuming */
+               rebind_evtchn_irq(xen_store_evtchn, xenbus_irq);
+       } else {
+               int err;
+               err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting,
+                                               0, "xenbus", &xb_waitq);
+               if (err <= 0) {
+                       printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+                       return err;
+               }
 
-       err = bind_evtchn_to_irqhandler(
-               xen_store_evtchn, wake_waiting,
-               0, "xenbus", &xb_waitq);
-       if (err <= 0) {
-               printk(KERN_ERR "XENBUS request irq failed %i\n", err);
-               return err;
+               xenbus_irq = err;
        }
 
-       xenbus_irq = err;
-
        return 0;
 }
index 227d53b12a5cc05490687f6e9f3c9e5725b147f2..7f2f91c0e11dc0c8e5a343c6400ec664faadd824 100644 (file)
@@ -283,9 +283,9 @@ static char *join(const char *dir, const char *name)
        char *buffer;
 
        if (strlen(name) == 0)
-               buffer = kasprintf(GFP_KERNEL, "%s", dir);
+               buffer = kasprintf(GFP_NOIO | __GFP_HIGH, "%s", dir);
        else
-               buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+               buffer = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/%s", dir, name);
        return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
 }
 
@@ -297,7 +297,7 @@ static char **split(char *strings, unsigned int len, unsigned int *num)
        *num = count_strings(strings, len);
 
        /* Transfer to one big alloc for easy freeing. */
-       ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+       ret = kmalloc(*num * sizeof(char *) + len, GFP_NOIO | __GFP_HIGH);
        if (!ret) {
                kfree(strings);
                return ERR_PTR(-ENOMEM);
@@ -751,7 +751,7 @@ static int process_msg(void)
        }
 
 
-       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+       msg = kmalloc(sizeof(*msg), GFP_NOIO | __GFP_HIGH);
        if (msg == NULL) {
                err = -ENOMEM;
                goto out;
@@ -763,7 +763,7 @@ static int process_msg(void)
                goto out;
        }
 
-       body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+       body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH);
        if (body == NULL) {
                kfree(msg);
                err = -ENOMEM;
index 2694648cbd1b6e7d235bc6dbb46cffa62482294d..313b2e06ded5dd525dcb9c9c422800564aacbe5b 100644 (file)
@@ -930,7 +930,7 @@ config PROC_KCORE
 
 config PROC_VMCORE
         bool "/proc/vmcore support (EXPERIMENTAL)"
-        depends on PROC_FS && EXPERIMENTAL && CRASH_DUMP
+        depends on PROC_FS && CRASH_DUMP
        default y
         help
         Exports the dump image of crashed kernel in ELF format.
index 1e7a11bd4da116f888a4589925dea958fa6ec5f9..277b079dec9e4751959db2688e69f5d17ed671de 100644 (file)
@@ -19,6 +19,7 @@ else
 obj-y +=       no-block.o
 endif
 
+obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o
 obj-$(CONFIG_INOTIFY)          += inotify.o
 obj-$(CONFIG_INOTIFY_USER)     += inotify_user.o
 obj-$(CONFIG_EPOLL)            += eventpoll.o
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
new file mode 100644 (file)
index 0000000..63e2ee6
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * bio-integrity.c - bio data integrity extensions
+ *
+ * Copyright (C) 2007, 2008 Oracle Corporation
+ * Written by: Martin K. Petersen <martin.petersen@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ */
+
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/bio.h>
+#include <linux/workqueue.h>
+
+static struct kmem_cache *bio_integrity_slab __read_mostly;
+static struct workqueue_struct *kintegrityd_wq;
+
+/**
+ * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio
+ * @bio:       bio to attach integrity metadata to
+ * @gfp_mask:  Memory allocation mask
+ * @nr_vecs:   Number of integrity metadata scatter-gather elements
+ * @bs:                bio_set to allocate from
+ *
+ * Description: This function prepares a bio for attaching integrity
+ * metadata.  nr_vecs specifies the maximum number of pages containing
+ * integrity metadata that can be attached.
+ */
+struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio,
+                                                        gfp_t gfp_mask,
+                                                        unsigned int nr_vecs,
+                                                        struct bio_set *bs)
+{
+       struct bio_integrity_payload *bip;
+       struct bio_vec *iv;
+       unsigned long idx;
+
+       BUG_ON(bio == NULL);
+
+       bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask);
+       if (unlikely(bip == NULL)) {
+               printk(KERN_ERR "%s: could not alloc bip\n", __func__);
+               return NULL;
+       }
+
+       memset(bip, 0, sizeof(*bip));
+
+       iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, bs);
+       if (unlikely(iv == NULL)) {
+               printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__);
+               mempool_free(bip, bs->bio_integrity_pool);
+               return NULL;
+       }
+
+       bip->bip_pool = idx;
+       bip->bip_vec = iv;
+       bip->bip_bio = bio;
+       bio->bi_integrity = bip;
+
+       return bip;
+}
+EXPORT_SYMBOL(bio_integrity_alloc_bioset);
+
+/**
+ * bio_integrity_alloc - Allocate integrity payload and attach it to bio
+ * @bio:       bio to attach integrity metadata to
+ * @gfp_mask:  Memory allocation mask
+ * @nr_vecs:   Number of integrity metadata scatter-gather elements
+ *
+ * Description: This function prepares a bio for attaching integrity
+ * metadata.  nr_vecs specifies the maximum number of pages containing
+ * integrity metadata that can be attached.
+ */
+struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
+                                                 gfp_t gfp_mask,
+                                                 unsigned int nr_vecs)
+{
+       return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set);
+}
+EXPORT_SYMBOL(bio_integrity_alloc);
+
+/**
+ * bio_integrity_free - Free bio integrity payload
+ * @bio:       bio containing bip to be freed
+ * @bs:                bio_set this bio was allocated from
+ *
+ * Description: Used to free the integrity portion of a bio. Usually
+ * called from bio_free().
+ */
+void bio_integrity_free(struct bio *bio, struct bio_set *bs)
+{
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+
+       BUG_ON(bip == NULL);
+
+       /* A cloned bio doesn't own the integrity metadata */
+       if (!bio_flagged(bio, BIO_CLONED) && bip->bip_buf != NULL)
+               kfree(bip->bip_buf);
+
+       mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]);
+       mempool_free(bip, bs->bio_integrity_pool);
+
+       bio->bi_integrity = NULL;
+}
+EXPORT_SYMBOL(bio_integrity_free);
+
+/**
+ * bio_integrity_add_page - Attach integrity metadata
+ * @bio:       bio to update
+ * @page:      page containing integrity metadata
+ * @len:       number of bytes of integrity metadata in page
+ * @offset:    start offset within page
+ *
+ * Description: Attach a page containing integrity metadata to bio.
+ */
+int bio_integrity_add_page(struct bio *bio, struct page *page,
+                          unsigned int len, unsigned int offset)
+{
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+       struct bio_vec *iv;
+
+       if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) {
+               printk(KERN_ERR "%s: bip_vec full\n", __func__);
+               return 0;
+       }
+
+       iv = bip_vec_idx(bip, bip->bip_vcnt);
+       BUG_ON(iv == NULL);
+       BUG_ON(iv->bv_page != NULL);
+
+       iv->bv_page = page;
+       iv->bv_len = len;
+       iv->bv_offset = offset;
+       bip->bip_vcnt++;
+
+       return len;
+}
+EXPORT_SYMBOL(bio_integrity_add_page);
+
+/**
+ * bio_integrity_enabled - Check whether integrity can be passed
+ * @bio:       bio to check
+ *
+ * Description: Determines whether bio_integrity_prep() can be called
+ * on this bio or not. bio data direction and target device must be
+ * set prior to calling.  The functions honors the write_generate and
+ * read_verify flags in sysfs.
+ */
+int bio_integrity_enabled(struct bio *bio)
+{
+       /* Already protected? */
+       if (bio_integrity(bio))
+               return 0;
+
+       return bdev_integrity_enabled(bio->bi_bdev, bio_data_dir(bio));
+}
+EXPORT_SYMBOL(bio_integrity_enabled);
+
+/**
+ * bio_integrity_hw_sectors - Convert 512b sectors to hardware ditto
+ * @bi:                blk_integrity profile for device
+ * @sectors:   Number of 512 sectors to convert
+ *
+ * Description: The block layer calculates everything in 512 byte
+ * sectors but integrity metadata is done in terms of the hardware
+ * sector size of the storage device.  Convert the block layer sectors
+ * to physical sectors.
+ */
+static inline unsigned int bio_integrity_hw_sectors(struct blk_integrity *bi,
+                                                   unsigned int sectors)
+{
+       /* At this point there are only 512b or 4096b DIF/EPP devices */
+       if (bi->sector_size == 4096)
+               return sectors >>= 3;
+
+       return sectors;
+}
+
+/**
+ * bio_integrity_tag_size - Retrieve integrity tag space
+ * @bio:       bio to inspect
+ *
+ * Description: Returns the maximum number of tag bytes that can be
+ * attached to this bio. Filesystems can use this to determine how
+ * much metadata to attach to an I/O.
+ */
+unsigned int bio_integrity_tag_size(struct bio *bio)
+{
+       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+
+       BUG_ON(bio->bi_size == 0);
+
+       return bi->tag_size * (bio->bi_size / bi->sector_size);
+}
+EXPORT_SYMBOL(bio_integrity_tag_size);
+
+int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set)
+{
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+       unsigned int nr_sectors;
+
+       BUG_ON(bip->bip_buf == NULL);
+
+       if (bi->tag_size == 0)
+               return -1;
+
+       nr_sectors = bio_integrity_hw_sectors(bi,
+                                       DIV_ROUND_UP(len, bi->tag_size));
+
+       if (nr_sectors * bi->tuple_size > bip->bip_size) {
+               printk(KERN_ERR "%s: tag too big for bio: %u > %u\n",
+                      __func__, nr_sectors * bi->tuple_size, bip->bip_size);
+               return -1;
+       }
+
+       if (set)
+               bi->set_tag_fn(bip->bip_buf, tag_buf, nr_sectors);
+       else
+               bi->get_tag_fn(bip->bip_buf, tag_buf, nr_sectors);
+
+       return 0;
+}
+
+/**
+ * bio_integrity_set_tag - Attach a tag buffer to a bio
+ * @bio:       bio to attach buffer to
+ * @tag_buf:   Pointer to a buffer containing tag data
+ * @len:       Length of the included buffer
+ *
+ * Description: Use this function to tag a bio by leveraging the extra
+ * space provided by devices formatted with integrity protection.  The
+ * size of the integrity buffer must be <= to the size reported by
+ * bio_integrity_tag_size().
+ */
+int bio_integrity_set_tag(struct bio *bio, void *tag_buf, unsigned int len)
+{
+       BUG_ON(bio_data_dir(bio) != WRITE);
+
+       return bio_integrity_tag(bio, tag_buf, len, 1);
+}
+EXPORT_SYMBOL(bio_integrity_set_tag);
+
+/**
+ * bio_integrity_get_tag - Retrieve a tag buffer from a bio
+ * @bio:       bio to retrieve buffer from
+ * @tag_buf:   Pointer to a buffer for the tag data
+ * @len:       Length of the target buffer
+ *
+ * Description: Use this function to retrieve the tag buffer from a
+ * completed I/O. The size of the integrity buffer must be <= to the
+ * size reported by bio_integrity_tag_size().
+ */
+int bio_integrity_get_tag(struct bio *bio, void *tag_buf, unsigned int len)
+{
+       BUG_ON(bio_data_dir(bio) != READ);
+
+       return bio_integrity_tag(bio, tag_buf, len, 0);
+}
+EXPORT_SYMBOL(bio_integrity_get_tag);
+
+/**
+ * bio_integrity_generate - Generate integrity metadata for a bio
+ * @bio:       bio to generate integrity metadata for
+ *
+ * Description: Generates integrity metadata for a bio by calling the
+ * block device's generation callback function.  The bio must have a
+ * bip attached with enough room to accommodate the generated
+ * integrity metadata.
+ */
+static void bio_integrity_generate(struct bio *bio)
+{
+       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+       struct blk_integrity_exchg bix;
+       struct bio_vec *bv;
+       sector_t sector = bio->bi_sector;
+       unsigned int i, sectors, total;
+       void *prot_buf = bio->bi_integrity->bip_buf;
+
+       total = 0;
+       bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
+       bix.sector_size = bi->sector_size;
+
+       bio_for_each_segment(bv, bio, i) {
+               void *kaddr = kmap_atomic(bv->bv_page, KM_USER0);
+               bix.data_buf = kaddr + bv->bv_offset;
+               bix.data_size = bv->bv_len;
+               bix.prot_buf = prot_buf;
+               bix.sector = sector;
+
+               bi->generate_fn(&bix);
+
+               sectors = bv->bv_len / bi->sector_size;
+               sector += sectors;
+               prot_buf += sectors * bi->tuple_size;
+               total += sectors * bi->tuple_size;
+               BUG_ON(total > bio->bi_integrity->bip_size);
+
+               kunmap_atomic(kaddr, KM_USER0);
+       }
+}
+
+/**
+ * bio_integrity_prep - Prepare bio for integrity I/O
+ * @bio:       bio to prepare
+ *
+ * Description: Allocates a buffer for integrity metadata, maps the
+ * pages and attaches them to a bio.  The bio must have data
+ * direction, target device and start sector set priot to calling.  In
+ * the WRITE case, integrity metadata will be generated using the
+ * block device's integrity function.  In the READ case, the buffer
+ * will be prepared for DMA and a suitable end_io handler set up.
+ */
+int bio_integrity_prep(struct bio *bio)
+{
+       struct bio_integrity_payload *bip;
+       struct blk_integrity *bi;
+       struct request_queue *q;
+       void *buf;
+       unsigned long start, end;
+       unsigned int len, nr_pages;
+       unsigned int bytes, offset, i;
+       unsigned int sectors;
+
+       bi = bdev_get_integrity(bio->bi_bdev);
+       q = bdev_get_queue(bio->bi_bdev);
+       BUG_ON(bi == NULL);
+       BUG_ON(bio_integrity(bio));
+
+       sectors = bio_integrity_hw_sectors(bi, bio_sectors(bio));
+
+       /* Allocate kernel buffer for protection data */
+       len = sectors * blk_integrity_tuple_size(bi);
+       buf = kmalloc(len, GFP_NOIO | __GFP_NOFAIL | q->bounce_gfp);
+       if (unlikely(buf == NULL)) {
+               printk(KERN_ERR "could not allocate integrity buffer\n");
+               return -EIO;
+       }
+
+       end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       start = ((unsigned long) buf) >> PAGE_SHIFT;
+       nr_pages = end - start;
+
+       /* Allocate bio integrity payload and integrity vectors */
+       bip = bio_integrity_alloc(bio, GFP_NOIO, nr_pages);
+       if (unlikely(bip == NULL)) {
+               printk(KERN_ERR "could not allocate data integrity bioset\n");
+               kfree(buf);
+               return -EIO;
+       }
+
+       bip->bip_buf = buf;
+       bip->bip_size = len;
+       bip->bip_sector = bio->bi_sector;
+
+       /* Map it */
+       offset = offset_in_page(buf);
+       for (i = 0 ; i < nr_pages ; i++) {
+               int ret;
+               bytes = PAGE_SIZE - offset;
+
+               if (len <= 0)
+                       break;
+
+               if (bytes > len)
+                       bytes = len;
+
+               ret = bio_integrity_add_page(bio, virt_to_page(buf),
+                                            bytes, offset);
+
+               if (ret == 0)
+                       return 0;
+
+               if (ret < bytes)
+                       break;
+
+               buf += bytes;
+               len -= bytes;
+               offset = 0;
+       }
+
+       /* Install custom I/O completion handler if read verify is enabled */
+       if (bio_data_dir(bio) == READ) {
+               bip->bip_end_io = bio->bi_end_io;
+               bio->bi_end_io = bio_integrity_endio;
+       }
+
+       /* Auto-generate integrity metadata if this is a write */
+       if (bio_data_dir(bio) == WRITE)
+               bio_integrity_generate(bio);
+
+       return 0;
+}
+EXPORT_SYMBOL(bio_integrity_prep);
+
+/**
+ * bio_integrity_verify - Verify integrity metadata for a bio
+ * @bio:       bio to verify
+ *
+ * Description: This function is called to verify the integrity of a
+ * bio.         The data in the bio io_vec is compared to the integrity
+ * metadata returned by the HBA.
+ */
+static int bio_integrity_verify(struct bio *bio)
+{
+       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+       struct blk_integrity_exchg bix;
+       struct bio_vec *bv;
+       sector_t sector = bio->bi_integrity->bip_sector;
+       unsigned int i, sectors, total, ret;
+       void *prot_buf = bio->bi_integrity->bip_buf;
+
+       ret = total = 0;
+       bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
+       bix.sector_size = bi->sector_size;
+
+       bio_for_each_segment(bv, bio, i) {
+               void *kaddr = kmap_atomic(bv->bv_page, KM_USER0);
+               bix.data_buf = kaddr + bv->bv_offset;
+               bix.data_size = bv->bv_len;
+               bix.prot_buf = prot_buf;
+               bix.sector = sector;
+
+               ret = bi->verify_fn(&bix);
+
+               if (ret) {
+                       kunmap_atomic(kaddr, KM_USER0);
+                       break;
+               }
+
+               sectors = bv->bv_len / bi->sector_size;
+               sector += sectors;
+               prot_buf += sectors * bi->tuple_size;
+               total += sectors * bi->tuple_size;
+               BUG_ON(total > bio->bi_integrity->bip_size);
+
+               kunmap_atomic(kaddr, KM_USER0);
+       }
+
+       return ret;
+}
+
+/**
+ * bio_integrity_verify_fn - Integrity I/O completion worker
+ * @work:      Work struct stored in bio to be verified
+ *
+ * Description: This workqueue function is called to complete a READ
+ * request.  The function verifies the transferred integrity metadata
+ * and then calls the original bio end_io function.
+ */
+static void bio_integrity_verify_fn(struct work_struct *work)
+{
+       struct bio_integrity_payload *bip =
+               container_of(work, struct bio_integrity_payload, bip_work);
+       struct bio *bio = bip->bip_bio;
+       int error = bip->bip_error;
+
+       if (bio_integrity_verify(bio)) {
+               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+               error = -EIO;
+       }
+
+       /* Restore original bio completion handler */
+       bio->bi_end_io = bip->bip_end_io;
+
+       if (bio->bi_end_io)
+               bio->bi_end_io(bio, error);
+}
+
+/**
+ * bio_integrity_endio - Integrity I/O completion function
+ * @bio:       Protected bio
+ * @error:     Pointer to errno
+ *
+ * Description: Completion for integrity I/O
+ *
+ * Normally I/O completion is done in interrupt context.  However,
+ * verifying I/O integrity is a time-consuming task which must be run
+ * in process context. This function postpones completion
+ * accordingly.
+ */
+void bio_integrity_endio(struct bio *bio, int error)
+{
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+
+       BUG_ON(bip->bip_bio != bio);
+
+       bip->bip_error = error;
+       INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
+       queue_work(kintegrityd_wq, &bip->bip_work);
+}
+EXPORT_SYMBOL(bio_integrity_endio);
+
+/**
+ * bio_integrity_mark_head - Advance bip_vec skip bytes
+ * @bip:       Integrity vector to advance
+ * @skip:      Number of bytes to advance it
+ */
+void bio_integrity_mark_head(struct bio_integrity_payload *bip,
+                            unsigned int skip)
+{
+       struct bio_vec *iv;
+       unsigned int i;
+
+       bip_for_each_vec(iv, bip, i) {
+               if (skip == 0) {
+                       bip->bip_idx = i;
+                       return;
+               } else if (skip >= iv->bv_len) {
+                       skip -= iv->bv_len;
+               } else { /* skip < iv->bv_len) */
+                       iv->bv_offset += skip;
+                       iv->bv_len -= skip;
+                       bip->bip_idx = i;
+                       return;
+               }
+       }
+}
+
+/**
+ * bio_integrity_mark_tail - Truncate bip_vec to be len bytes long
+ * @bip:       Integrity vector to truncate
+ * @len:       New length of integrity vector
+ */
+void bio_integrity_mark_tail(struct bio_integrity_payload *bip,
+                            unsigned int len)
+{
+       struct bio_vec *iv;
+       unsigned int i;
+
+       bip_for_each_vec(iv, bip, i) {
+               if (len == 0) {
+                       bip->bip_vcnt = i;
+                       return;
+               } else if (len >= iv->bv_len) {
+                       len -= iv->bv_len;
+               } else { /* len < iv->bv_len) */
+                       iv->bv_len = len;
+                       len = 0;
+               }
+       }
+}
+
+/**
+ * bio_integrity_advance - Advance integrity vector
+ * @bio:       bio whose integrity vector to update
+ * @bytes_done:        number of data bytes that have been completed
+ *
+ * Description: This function calculates how many integrity bytes the
+ * number of completed data bytes correspond to and advances the
+ * integrity vector accordingly.
+ */
+void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
+{
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+       unsigned int nr_sectors;
+
+       BUG_ON(bip == NULL);
+       BUG_ON(bi == NULL);
+
+       nr_sectors = bio_integrity_hw_sectors(bi, bytes_done >> 9);
+       bio_integrity_mark_head(bip, nr_sectors * bi->tuple_size);
+}
+EXPORT_SYMBOL(bio_integrity_advance);
+
+/**
+ * bio_integrity_trim - Trim integrity vector
+ * @bio:       bio whose integrity vector to update
+ * @offset:    offset to first data sector
+ * @sectors:   number of data sectors
+ *
+ * Description: Used to trim the integrity vector in a cloned bio.
+ * The ivec will be advanced corresponding to 'offset' data sectors
+ * and the length will be truncated corresponding to 'len' data
+ * sectors.
+ */
+void bio_integrity_trim(struct bio *bio, unsigned int offset,
+                       unsigned int sectors)
+{
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+       struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
+       unsigned int nr_sectors;
+
+       BUG_ON(bip == NULL);
+       BUG_ON(bi == NULL);
+       BUG_ON(!bio_flagged(bio, BIO_CLONED));
+
+       nr_sectors = bio_integrity_hw_sectors(bi, sectors);
+       bip->bip_sector = bip->bip_sector + offset;
+       bio_integrity_mark_head(bip, offset * bi->tuple_size);
+       bio_integrity_mark_tail(bip, sectors * bi->tuple_size);
+}
+EXPORT_SYMBOL(bio_integrity_trim);
+
+/**
+ * bio_integrity_split - Split integrity metadata
+ * @bio:       Protected bio
+ * @bp:                Resulting bio_pair
+ * @sectors:   Offset
+ *
+ * Description: Splits an integrity page into a bio_pair.
+ */
+void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors)
+{
+       struct blk_integrity *bi;
+       struct bio_integrity_payload *bip = bio->bi_integrity;
+       unsigned int nr_sectors;
+
+       if (bio_integrity(bio) == 0)
+               return;
+
+       bi = bdev_get_integrity(bio->bi_bdev);
+       BUG_ON(bi == NULL);
+       BUG_ON(bip->bip_vcnt != 1);
+
+       nr_sectors = bio_integrity_hw_sectors(bi, sectors);
+
+       bp->bio1.bi_integrity = &bp->bip1;
+       bp->bio2.bi_integrity = &bp->bip2;
+
+       bp->iv1 = bip->bip_vec[0];
+       bp->iv2 = bip->bip_vec[0];
+
+       bp->bip1.bip_vec = &bp->iv1;
+       bp->bip2.bip_vec = &bp->iv2;
+
+       bp->iv1.bv_len = sectors * bi->tuple_size;
+       bp->iv2.bv_offset += sectors * bi->tuple_size;
+       bp->iv2.bv_len -= sectors * bi->tuple_size;
+
+       bp->bip1.bip_sector = bio->bi_integrity->bip_sector;
+       bp->bip2.bip_sector = bio->bi_integrity->bip_sector + nr_sectors;
+
+       bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1;
+       bp->bip1.bip_idx = bp->bip2.bip_idx = 0;
+}
+EXPORT_SYMBOL(bio_integrity_split);
+
+/**
+ * bio_integrity_clone - Callback for cloning bios with integrity metadata
+ * @bio:       New bio
+ * @bio_src:   Original bio
+ * @bs:                bio_set to allocate bip from
+ *
+ * Description:        Called to allocate a bip when cloning a bio
+ */
+int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
+                       struct bio_set *bs)
+{
+       struct bio_integrity_payload *bip_src = bio_src->bi_integrity;
+       struct bio_integrity_payload *bip;
+
+       BUG_ON(bip_src == NULL);
+
+       bip = bio_integrity_alloc_bioset(bio, GFP_NOIO, bip_src->bip_vcnt, bs);
+
+       if (bip == NULL)
+               return -EIO;
+
+       memcpy(bip->bip_vec, bip_src->bip_vec,
+              bip_src->bip_vcnt * sizeof(struct bio_vec));
+
+       bip->bip_sector = bip_src->bip_sector;
+       bip->bip_vcnt = bip_src->bip_vcnt;
+       bip->bip_idx = bip_src->bip_idx;
+
+       return 0;
+}
+EXPORT_SYMBOL(bio_integrity_clone);
+
+int bioset_integrity_create(struct bio_set *bs, int pool_size)
+{
+       bs->bio_integrity_pool = mempool_create_slab_pool(pool_size,
+                                                         bio_integrity_slab);
+       if (!bs->bio_integrity_pool)
+               return -1;
+
+       return 0;
+}
+EXPORT_SYMBOL(bioset_integrity_create);
+
+void bioset_integrity_free(struct bio_set *bs)
+{
+       if (bs->bio_integrity_pool)
+               mempool_destroy(bs->bio_integrity_pool);
+}
+EXPORT_SYMBOL(bioset_integrity_free);
+
+void __init bio_integrity_init_slab(void)
+{
+       bio_integrity_slab = KMEM_CACHE(bio_integrity_payload,
+                                       SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+}
+EXPORT_SYMBOL(bio_integrity_init_slab);
+
+static int __init integrity_init(void)
+{
+       kintegrityd_wq = create_workqueue("kintegrityd");
+
+       if (!kintegrityd_wq)
+               panic("Failed to create kintegrityd\n");
+
+       return 0;
+}
+subsys_initcall(integrity_init);
index 78562574cb524d87b06883bce5002542b77b5865..88322b066acb68f8279e79eeca5842c6b02bd8ce 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
 #include <linux/blktrace_api.h>
 #include <scsi/sg.h>           /* for struct sg_iovec */
 
-#define BIO_POOL_SIZE 2
-
 static struct kmem_cache *bio_slab __read_mostly;
 
-#define BIOVEC_NR_POOLS 6
-
-/*
- * a small number of entries is fine, not going to be performance critical.
- * basically we just need to survive
- */
-#define BIO_SPLIT_ENTRIES 2
 mempool_t *bio_split_pool __read_mostly;
 
-struct biovec_slab {
-       int nr_vecs;
-       char *name; 
-       struct kmem_cache *slab;
-};
-
 /*
  * if you change this list, also change bvec_alloc or things will
  * break badly! cannot be bigger than what you can fit into an
@@ -59,24 +44,18 @@ static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
 };
 #undef BV
 
-/*
- * bio_set is used to allow other portions of the IO system to
- * allocate their own private memory pools for bio and iovec structures.
- * These memory pools in turn all allocate from the bio_slab
- * and the bvec_slabs[].
- */
-struct bio_set {
-       mempool_t *bio_pool;
-       mempool_t *bvec_pools[BIOVEC_NR_POOLS];
-};
-
 /*
  * fs_bio_set is the bio_set containing bio and iovec memory pools used by
  * IO code that does not need private memory pools.
  */
-static struct bio_set *fs_bio_set;
+struct bio_set *fs_bio_set;
+
+unsigned int bvec_nr_vecs(unsigned short idx)
+{
+       return bvec_slabs[idx].nr_vecs;
+}
 
-static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
+struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
 {
        struct bio_vec *bvl;
 
@@ -117,6 +96,9 @@ void bio_free(struct bio *bio, struct bio_set *bio_set)
                mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
        }
 
+       if (bio_integrity(bio))
+               bio_integrity_free(bio, bio_set);
+
        mempool_free(bio, bio_set->bio_pool);
 }
 
@@ -275,9 +257,19 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
 {
        struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set);
 
-       if (b) {
-               b->bi_destructor = bio_fs_destructor;
-               __bio_clone(b, bio);
+       if (!b)
+               return NULL;
+
+       b->bi_destructor = bio_fs_destructor;
+       __bio_clone(b, bio);
+
+       if (bio_integrity(bio)) {
+               int ret;
+
+               ret = bio_integrity_clone(b, bio, fs_bio_set);
+
+               if (ret < 0)
+                       return NULL;
        }
 
        return b;
@@ -333,10 +325,19 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                if (page == prev->bv_page &&
                    offset == prev->bv_offset + prev->bv_len) {
                        prev->bv_len += len;
-                       if (q->merge_bvec_fn &&
-                           q->merge_bvec_fn(q, bio, prev) < len) {
-                               prev->bv_len -= len;
-                               return 0;
+
+                       if (q->merge_bvec_fn) {
+                               struct bvec_merge_data bvm = {
+                                       .bi_bdev = bio->bi_bdev,
+                                       .bi_sector = bio->bi_sector,
+                                       .bi_size = bio->bi_size,
+                                       .bi_rw = bio->bi_rw,
+                               };
+
+                               if (q->merge_bvec_fn(q, &bvm, prev) < len) {
+                                       prev->bv_len -= len;
+                                       return 0;
+                               }
                        }
 
                        goto done;
@@ -377,11 +378,18 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
         * queue to get further control
         */
        if (q->merge_bvec_fn) {
+               struct bvec_merge_data bvm = {
+                       .bi_bdev = bio->bi_bdev,
+                       .bi_sector = bio->bi_sector,
+                       .bi_size = bio->bi_size,
+                       .bi_rw = bio->bi_rw,
+               };
+
                /*
                 * merge_bvec_fn() returns number of bytes it can accept
                 * at this offset
                 */
-               if (q->merge_bvec_fn(q, bio, bvec) < len) {
+               if (q->merge_bvec_fn(q, &bvm, bvec) < len) {
                        bvec->bv_page = NULL;
                        bvec->bv_len = 0;
                        bvec->bv_offset = 0;
@@ -1249,6 +1257,9 @@ struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors)
        bp->bio1.bi_private = bi;
        bp->bio2.bi_private = pool;
 
+       if (bio_integrity(bi))
+               bio_integrity_split(bi, bp, first_sectors);
+
        return bp;
 }
 
@@ -1290,6 +1301,7 @@ void bioset_free(struct bio_set *bs)
        if (bs->bio_pool)
                mempool_destroy(bs->bio_pool);
 
+       bioset_integrity_free(bs);
        biovec_free_pools(bs);
 
        kfree(bs);
@@ -1306,6 +1318,9 @@ struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
        if (!bs->bio_pool)
                goto bad;
 
+       if (bioset_integrity_create(bs, bio_pool_size))
+               goto bad;
+
        if (!biovec_create_pools(bs, bvec_pool_size))
                return bs;
 
@@ -1332,6 +1347,7 @@ static int __init init_bio(void)
 {
        bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
+       bio_integrity_init_slab();
        biovec_init_slabs();
 
        fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
index 4fc302c2a0e0f886e4026288bcdc50888ddf3551..4f6f7635b59c93c0c2a86a8deff1f59c567de9f5 100644 (file)
@@ -750,7 +750,7 @@ struct proc_fs_info {
        const char *str;
 };
 
-static void show_sb_opts(struct seq_file *m, struct super_block *sb)
+static int show_sb_opts(struct seq_file *m, struct super_block *sb)
 {
        static const struct proc_fs_info fs_info[] = {
                { MS_SYNCHRONOUS, ",sync" },
@@ -764,6 +764,8 @@ static void show_sb_opts(struct seq_file *m, struct super_block *sb)
                if (sb->s_flags & fs_infop->flag)
                        seq_puts(m, fs_infop->str);
        }
+
+       return security_sb_show_options(m, sb);
 }
 
 static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
@@ -806,11 +808,14 @@ static int show_vfsmnt(struct seq_file *m, void *v)
        seq_putc(m, ' ');
        show_type(m, mnt->mnt_sb);
        seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
-       show_sb_opts(m, mnt->mnt_sb);
+       err = show_sb_opts(m, mnt->mnt_sb);
+       if (err)
+               goto out;
        show_mnt_opts(m, mnt);
        if (mnt->mnt_sb->s_op->show_options)
                err = mnt->mnt_sb->s_op->show_options(m, mnt);
        seq_puts(m, " 0 0\n");
+out:
        return err;
 }
 
@@ -865,10 +870,13 @@ static int show_mountinfo(struct seq_file *m, void *v)
        seq_putc(m, ' ');
        mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
        seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
-       show_sb_opts(m, sb);
+       err = show_sb_opts(m, sb);
+       if (err)
+               goto out;
        if (sb->s_op->show_options)
                err = sb->s_op->show_options(m, mnt);
        seq_putc(m, '\n');
+out:
        return err;
 }
 
index 3b455371e7ff50981229d98359344ef92a228d0e..58c3e6a8e15e160ec3d6af3aabe6138b666b00b8 100644 (file)
@@ -233,7 +233,7 @@ static int check_mem_permission(struct task_struct *task)
         */
        if (task->parent == current && (task->ptrace & PT_PTRACED) &&
            task_is_stopped_or_traced(task) &&
-           ptrace_may_attach(task))
+           ptrace_may_access(task, PTRACE_MODE_ATTACH))
                return 0;
 
        /*
@@ -251,7 +251,8 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
        task_lock(task);
        if (task->mm != mm)
                goto out;
-       if (task->mm != current->mm && __ptrace_may_attach(task) < 0)
+       if (task->mm != current->mm &&
+           __ptrace_may_access(task, PTRACE_MODE_READ) < 0)
                goto out;
        task_unlock(task);
        return mm;
@@ -518,7 +519,7 @@ static int proc_fd_access_allowed(struct inode *inode)
         */
        task = get_proc_task(inode);
        if (task) {
-               allowed = ptrace_may_attach(task);
+               allowed = ptrace_may_access(task, PTRACE_MODE_READ);
                put_task_struct(task);
        }
        return allowed;
@@ -904,7 +905,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
        if (!task)
                goto out_no_task;
 
-       if (!ptrace_may_attach(task))
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
                goto out;
 
        ret = -ENOMEM;
index 7e277f2ad466da31d9233a06f17963c718c37397..c652d469dc08deeb25b057ca4675d857b9db79bb 100644 (file)
@@ -123,6 +123,11 @@ static int uptime_read_proc(char *page, char **start, off_t off,
        return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+int __attribute__((weak)) arch_report_meminfo(char *page)
+{
+       return 0;
+}
+
 static int meminfo_read_proc(char *page, char **start, off_t off,
                                 int count, int *eof, void *data)
 {
@@ -221,6 +226,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off,
 
                len += hugetlb_report_meminfo(page + len);
 
+       len += arch_report_meminfo(page + len);
+
        return proc_calc_metrics(page, start, off, count, eof, len);
 #undef K
 }
@@ -472,6 +479,13 @@ static const struct file_operations proc_vmalloc_operations = {
 };
 #endif
 
+#ifndef arch_irq_stat_cpu
+#define arch_irq_stat_cpu(cpu) 0
+#endif
+#ifndef arch_irq_stat
+#define arch_irq_stat() 0
+#endif
+
 static int show_stat(struct seq_file *p, void *v)
 {
        int i;
@@ -509,7 +523,9 @@ static int show_stat(struct seq_file *p, void *v)
                        sum += temp;
                        per_irq_sum[j] += temp;
                }
+               sum += arch_irq_stat_cpu(i);
        }
+       sum += arch_irq_stat();
 
        seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
                (unsigned long long)cputime64_to_clock_t(user),
index c492449f3b45057cba171121e7e2b08b934adbfc..164bd9f9ede3024188285d071bbc6caa47cb94f8 100644 (file)
@@ -210,7 +210,7 @@ static int show_map(struct seq_file *m, void *v)
        dev_t dev = 0;
        int len;
 
-       if (maps_protect && !ptrace_may_attach(task))
+       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
                return -EACCES;
 
        if (file) {
@@ -646,7 +646,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
                goto out;
 
        ret = -EACCES;
-       if (!ptrace_may_attach(task))
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
                goto out_task;
 
        ret = -EINVAL;
@@ -747,7 +747,7 @@ static int show_numa_map_checked(struct seq_file *m, void *v)
        struct proc_maps_private *priv = m->private;
        struct task_struct *task = priv->task;
 
-       if (maps_protect && !ptrace_may_attach(task))
+       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
                return -EACCES;
 
        return show_numa_map(m, v);
index 4b4f9cc2f186a72705a2525367b8861b6889a0ad..5d84e7121df819cd0d9eb8b9bd54973edf5b77ed 100644 (file)
@@ -113,7 +113,7 @@ static int show_map(struct seq_file *m, void *_vml)
        struct proc_maps_private *priv = m->private;
        struct task_struct *task = priv->task;
 
-       if (maps_protect && !ptrace_may_attach(task))
+       if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
                return -EACCES;
 
        return nommu_vma_show(m, vml->vma);
index 9590b90243002f084cc4a51e8b1bd25ca0cef8f4..78f613cb9c7638529f9a587c3d65e69f3154841f 100644 (file)
@@ -45,6 +45,7 @@ const struct file_operations ramfs_file_operations = {
        .mmap           = generic_file_mmap,
        .fsync          = simple_sync_file,
        .splice_read    = generic_file_splice_read,
+       .splice_write   = generic_file_splice_write,
        .llseek         = generic_file_llseek,
 };
 
index 0989bc2c2f6921be4d54b57066c6f1e163f9f546..52312ec93ff4ae5c0753cdb37af0991f1f733a4c 100644 (file)
@@ -43,6 +43,7 @@ const struct file_operations ramfs_file_operations = {
        .aio_write              = generic_file_aio_write,
        .fsync                  = simple_sync_file,
        .splice_read            = generic_file_splice_read,
+       .splice_write           = generic_file_splice_write,
        .llseek                 = generic_file_llseek,
 };
 
index aa5f6f60b3055f8a35b59084f0c652cb0e5c2125..399442179d89d5821b4caccc488fb0180e4e35c0 100644 (file)
@@ -379,13 +379,22 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
                                lock_page(page);
 
                        /*
-                        * page was truncated, stop here. if this isn't the
-                        * first page, we'll just complete what we already
-                        * added
+                        * Page was truncated, or invalidated by the
+                        * filesystem.  Redo the find/create, but this time the
+                        * page is kept locked, so there's no chance of another
+                        * race with truncate/invalidate.
                         */
                        if (!page->mapping) {
                                unlock_page(page);
-                               break;
+                               page = find_or_create_page(mapping, index,
+                                               mapping_gfp_mask(mapping));
+
+                               if (!page) {
+                                       error = -ENOMEM;
+                                       break;
+                               }
+                               page_cache_release(pages[page_nr]);
+                               pages[page_nr] = page;
                        }
                        /*
                         * page was already under io and is now done, great
index b52288774345deaf39d422aaa380c85590b36772..bdca155028ecd343b4ebf0182904dc83f1e61469 100644 (file)
@@ -4,5 +4,6 @@ header-y += sound/
 header-y += mtd/
 header-y += rdma/
 header-y += video/
+header-y += drm/
 
 header-y += asm-$(ARCH)/
index a4e2d28bfb5884c52af09f110fa543d776386f57..b4cddfaca90ec7d42b7637eb7a46c86887d8657f 100644 (file)
@@ -8,6 +8,12 @@
 
 #define GPIO_PIN_NONE  (-1)
 
+/*
+ * Clock rates for various on-board oscillators. The number of entries
+ * in this array is chip-dependent.
+ */
+extern unsigned long at32_board_osc_rates[];
+  
 /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
 void at32_add_system_devices(void);
 
@@ -36,7 +42,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n);
 struct atmel_lcdfb_info;
 struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len);
+                    unsigned long fbmem_start, unsigned long fbmem_len,
+                    unsigned int pin_config);
 
 struct usba_platform_data;
 struct platform_device *
@@ -73,6 +80,7 @@ struct platform_device *at32_add_device_twi(unsigned int id,
 struct platform_device *at32_add_device_mci(unsigned int id);
 struct platform_device *at32_add_device_ac97c(unsigned int id);
 struct platform_device *at32_add_device_abdac(unsigned int id);
+struct platform_device *at32_add_device_psif(unsigned int id);
 
 struct cf_platform_data {
        int     detect_pin;
index 5e75d850d7076409ecd6fea47adfb36412736886..bc40e3d461503aa9a77c344e8d9aba520d7dc541 100644 (file)
 void setup_platform(void);
 void setup_board(void);
 
-/* Called by setup_platform */
-void at32_clock_init(void);
-void at32_portmux_init(void);
-
 void at32_setup_serial_console(unsigned int usart_id);
 
 #endif /* __ASM_AVR32_AT32AP_INIT_H__ */
index 356e43064903cdb48d9b2d8f00468585a16bc970..979b355b77b652c3946d0e22db820c4d3dd142cd 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifndef __ASSEMBLY__
 extern void cpu_enter_idle(void);
+extern void cpu_enter_standby(unsigned long sdramc_base);
 
 extern bool disable_idle_sleep;
 
@@ -43,6 +44,8 @@ static inline void cpu_idle_sleep(void)
        else
                cpu_enter_idle();
 }
+
+void intc_set_suspend_handler(unsigned long offset);
 #endif
 
 #endif /* __ASM_AVR32_ARCH_PM_H */
diff --git a/include/asm-avr32/arch-at32ap/sram.h b/include/asm-avr32/arch-at32ap/sram.h
new file mode 100644 (file)
index 0000000..4838dae
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Simple SRAM allocator
+ *
+ * Copyright (C) 2008 Atmel 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.
+ */
+#ifndef __ASM_AVR32_ARCH_SRAM_H
+#define __ASM_AVR32_ARCH_SRAM_H
+
+#include <linux/genalloc.h>
+
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+       if (!sram_pool)
+               return 0UL;
+
+       return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+       return gen_pool_free(sram_pool, addr, len);
+}
+
+#endif /* __ASM_AVR32_ARCH_SRAM_H */
index c37c391faef6b0f67d50cbe1bfed504dbdc9d36f..27ff234071009b19e9f5f5dbeeadc52cefbcf0e1 100644 (file)
@@ -13,7 +13,6 @@
 #define __ASM_AVR32_MMU_CONTEXT_H
 
 #include <asm/tlbflush.h>
-#include <asm/pgalloc.h>
 #include <asm/sysreg.h>
 #include <asm-generic/mm_hooks.h>
 
index 0f5f134b896a132635b412c83a772ba86ea78fa6..a32a02372017443d24db8848d2a559c548b1f13e 100644 (file)
@@ -5,4 +5,6 @@
 
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
+#include <asm-generic/pci-dma-compat.h>
+
 #endif /* __ASM_AVR32_PCI_H__ */
index 51fc1f6e4b17afb9d73b7065ad6bea459549d205..64082132394312a4c861abdc6b110f58517a7a40 100644 (file)
@@ -8,65 +8,79 @@
 #ifndef __ASM_AVR32_PGALLOC_H
 #define __ASM_AVR32_PGALLOC_H
 
-#include <asm/processor.h>
-#include <linux/threads.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
+#include <linux/quicklist.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
-#define pmd_populate_kernel(mm, pmd, pte) \
-       set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
+#define QUICK_PGD      0       /* Preserve kernel mappings over free */
+#define QUICK_PT       1       /* Zero on free */
 
-static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+static inline void pmd_populate_kernel(struct mm_struct *mm,
+                                      pmd_t *pmd, pte_t *pte)
+{
+       set_pmd(pmd, __pmd((unsigned long)pte));
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
                                    pgtable_t pte)
 {
-       set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
+       set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
+static inline void pgd_ctor(void *x)
+{
+       pgd_t *pgd = x;
+
+       memcpy(pgd + USER_PTRS_PER_PGD,
+               swapper_pg_dir + USER_PTRS_PER_PGD,
+               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
 /*
  * Allocate and free page tables
  */
-static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
+       return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
 }
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-       kfree(pgd);
+       quicklist_free(QUICK_PGD, NULL, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                          unsigned long address)
 {
-       pte_t *pte;
-
-       pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
-
-       return pte;
+       return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
 }
 
-static inline struct page *pte_alloc_one(struct mm_struct *mm,
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
                                         unsigned long address)
 {
-       struct page *pte;
+       struct page *page;
+       void *pg;
 
-       pte = alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
-       if (!pte)
+       pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
+       if (!pg)
                return NULL;
-       pgtable_page_ctor(pte);
-       return pte;
+
+       page = virt_to_page(pg);
+       pgtable_page_ctor(page);
+
+       return page;
 }
 
 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
-       free_page((unsigned long)pte);
+       quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
 {
        pgtable_page_dtor(pte);
-       __free_page(pte);
+       quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
 #define __pte_free_tlb(tlb,pte)                                \
@@ -75,6 +89,10 @@ do {                                                 \
        tlb_remove_page((tlb), pte);                    \
 } while (0)
 
-#define check_pgt_cache() do { } while(0)
+static inline void check_pgt_cache(void)
+{
+       quicklist_trim(QUICK_PGD, NULL, 25, 16);
+       quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 
 #endif /* __ASM_AVR32_PGALLOC_H */
index c0e5e29417df5454d9b286d32d326010ebcef463..fecdda16f4443a7ed957690eeb5ec57cd5d4f5ae 100644 (file)
@@ -129,13 +129,6 @@ extern struct page *empty_zero_page;
 
 #define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT)
 
-/* TODO: Check for saneness */
-/* User-mode page table flags (to be set in a pgd or pmd entry) */
-#define _PAGE_TABLE            (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
-                                | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-/* Kernel-mode page table flags */
-#define _KERNPG_TABLE          (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
-                                | _PAGE_ACCESSED | _PAGE_DIRTY)
 /* Flags that may be modified by software */
 #define _PAGE_CHG_MASK         (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \
                                 | _PAGE_FLAGS_CACHE_MASK)
@@ -262,10 +255,14 @@ static inline pte_t pte_mkspecial(pte_t pte)
 }
 
 #define pmd_none(x)    (!pmd_val(x))
-#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
-#define pmd_clear(xp)  do { set_pmd(xp, __pmd(0)); } while (0)
-#define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER))      \
-                        != _KERNPG_TABLE)
+#define pmd_present(x) (pmd_val(x))
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+       set_pmd(pmdp, __pmd(0));
+}
+
+#define        pmd_bad(x)      (pmd_val(x) & ~PAGE_MASK)
 
 /*
  * Permanent address of a page. We don't support highmem, so this is
@@ -303,19 +300,16 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 #define page_pte(page) page_pte_prot(page, __pgprot(0))
 
-#define pmd_page_vaddr(pmd)                                    \
-       ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
-#define pmd_page(pmd)  (phys_to_page(pmd_val(pmd)))
+#define pmd_page_vaddr(pmd)    pmd_val(pmd)
+#define pmd_page(pmd)          (virt_to_page(pmd_val(pmd)))
 
 /* to find an entry in a page-table-directory. */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
-#define pgd_offset_current(address)                            \
-       ((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address))
+#define pgd_index(address)     (((address) >> PGDIR_SHIFT)     \
+                                & (PTRS_PER_PGD - 1))
+#define pgd_offset(mm, address)        ((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pgd_offset_k(address)  pgd_offset(&init_mm, address)
 
 /* Find an entry in the third-level page table.. */
 #define pte_index(address)                             \
index 07049f6c0d41a168ba057eae80247a0f8727b03e..df68631b7b27f98f63e579a3a20940a544f84f6a 100644 (file)
@@ -88,6 +88,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             6
 #define TIF_RESTORE_SIGMASK    7       /* restore signal mask in do_signal */
 #define TIF_CPU_GOING_TO_SLEEP 8       /* CPU is entering sleep 0 mode */
+#define TIF_FREEZE             29
 #define TIF_DEBUG              30      /* debugging enabled */
 #define TIF_USERSPACE          31      /* true if FS sets userspace */
 
index 5bc7c88a5770a9c211d8aa6d32c2b04ed4186166..bf90a786f6be93dcda8aa4f1a1c06697a87f8b8f 100644 (file)
@@ -26,7 +26,6 @@ extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                            unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-extern void __flush_tlb_page(unsigned long asid, unsigned long page);
 
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
index 44ef329531c3b45b5809f120a80a920f145892b4..4fce3db2cecceefbc68785fa105345f6f60d502b 100644 (file)
@@ -197,6 +197,63 @@ static inline int pmd_none_or_clear_bad(pmd_t *pmd)
 }
 #endif /* CONFIG_MMU */
 
+static inline pte_t __ptep_modify_prot_start(struct mm_struct *mm,
+                                            unsigned long addr,
+                                            pte_t *ptep)
+{
+       /*
+        * Get the current pte state, but zero it out to make it
+        * non-present, preventing the hardware from asynchronously
+        * updating it.
+        */
+       return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline void __ptep_modify_prot_commit(struct mm_struct *mm,
+                                            unsigned long addr,
+                                            pte_t *ptep, pte_t pte)
+{
+       /*
+        * The pte is non-present, so there's no hardware state to
+        * preserve.
+        */
+       set_pte_at(mm, addr, ptep, pte);
+}
+
+#ifndef __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+/*
+ * Start a pte protection read-modify-write transaction, which
+ * protects against asynchronous hardware modifications to the pte.
+ * The intention is not to prevent the hardware from making pte
+ * updates, but to prevent any updates it may make from being lost.
+ *
+ * This does not protect against other software modifications of the
+ * pte; the appropriate pte lock must be held over the transation.
+ *
+ * Note that this interface is intended to be batchable, meaning that
+ * ptep_modify_prot_commit may not actually update the pte, but merely
+ * queue the update to be done at some later time.  The update must be
+ * actually committed before the pte lock is released, however.
+ */
+static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
+                                          unsigned long addr,
+                                          pte_t *ptep)
+{
+       return __ptep_modify_prot_start(mm, addr, ptep);
+}
+
+/*
+ * Commit an update to a pte, leaving any hardware-controlled bits in
+ * the PTE unmodified.
+ */
+static inline void ptep_modify_prot_commit(struct mm_struct *mm,
+                                          unsigned long addr,
+                                          pte_t *ptep, pte_t pte)
+{
+       __ptep_modify_prot_commit(mm, addr, ptep, pte);
+}
+#endif /* __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION */
+
 /*
  * A facility to provide lazy MMU batching.  This allows PTE updates and
  * page invalidations to be delayed until a call to leave lazy MMU mode
index a6aea79bca4f369b51f0e384e15bfabcdd7e13c5..54bbf6e04ee8f3bbd652c30254ef6553e38866c4 100644 (file)
@@ -60,7 +60,8 @@
 #ifndef node_to_cpumask_ptr
 
 #define        node_to_cpumask_ptr(v, node)                                    \
-               cpumask_t _##v = node_to_cpumask(node), *v = &_##v
+               cpumask_t _##v = node_to_cpumask(node);                 \
+               const cpumask_t *v = &_##v
 
 #define node_to_cpumask_ptr_next(v, node)                              \
                          _##v = node_to_cpumask(node)
index f054778e916c08e0b1e7cc85dd028de15b21edb2..f1992dc5c4248a21a6c71f7a546fdb21527d72a5 100644 (file)
@@ -93,6 +93,8 @@
                VMLINUX_SYMBOL(__end_rio_route_ops) = .;                \
        }                                                               \
                                                                        \
+       TRACEDATA                                                       \
+                                                                       \
        /* Kernel symbol table: Normal symbols */                       \
        __ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {         \
                VMLINUX_SYMBOL(__start___ksymtab) = .;                  \
                __stop___bug_table = .;                                 \
        }
 
+#ifdef CONFIG_PM_TRACE
+#define TRACEDATA                                                      \
+       . = ALIGN(4);                                                   \
+       .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {               \
+               __tracedata_start = .;                                  \
+               *(.tracedata)                                           \
+               __tracedata_end = .;                                    \
+       }
+#else
+#define TRACEDATA
+#endif
+
 #define NOTES                                                          \
        .notes : AT(ADDR(.notes) - LOAD_OFFSET) {                       \
                VMLINUX_SYMBOL(__start_notes) = .;                      \
index dae4eca2417e847fd47a3eb8f2009814f8c07a77..892b7f168eb47df60d0b18cf2d0abb26848ac552 100644 (file)
@@ -204,6 +204,14 @@ typedef struct     psc_i2s {
        u32     psc_i2sudf;
 } psc_i2s_t;
 
+#define PSC_I2SCFG_OFFSET      0x08
+#define PSC_I2SMASK_OFFSET     0x0C
+#define PSC_I2SPCR_OFFSET      0x10
+#define PSC_I2SSTAT_OFFSET     0x14
+#define PSC_I2SEVENT_OFFSET    0x18
+#define PSC_I2SRXTX_OFFSET     0x1C
+#define PSC_I2SUDF_OFFSET      0x20
+
 /* I2S Config Register. */
 #define PSC_I2SCFG_RT_MASK     (3 << 30)
 #define PSC_I2SCFG_RT_FIFO1    (0 << 30)
index 13c9805349f170deda0308100707ba856390a730..09f312501eb5f82828b3231ecadc06e9356411d0 100644 (file)
@@ -8,6 +8,9 @@ header-y += ucontext.h
 header-y += vtoc.h
 header-y += zcrypt.h
 header-y += kvm.h
+header-y += schid.h
+header-y += chsc.h
 
 unifdef-y += cmb.h
 unifdef-y += debug.h
+unifdef-y += chpid.h
index 41d028cb52a4a96843024966d60ed56c7df37d20..1ac80d6b05887815f0fceec4ed6e428c11849d99 100644 (file)
@@ -13,7 +13,7 @@
 
 typedef void (*adapter_int_handler_t)(void *, void *);
 
-void *s390_register_adapter_interrupt(adapter_int_handler_t, void *);
-void s390_unregister_adapter_interrupt(void *);
+void *s390_register_adapter_interrupt(adapter_int_handler_t, void *, u8);
+void s390_unregister_adapter_interrupt(void *, u8);
 
 #endif /* _ASM_S390_AIRQ_H */
index 066aa70518ce0b0c94e4d0380abd9940c520c02f..ba007d8df9411867260f9b75591219ed8872da0d 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
+#include <asm/fcx.h>
 
 /* structs from asm/cio.h */
 struct irb;
@@ -157,6 +158,17 @@ extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *,
 extern int ccw_device_resume(struct ccw_device *);
 extern int ccw_device_halt(struct ccw_device *, unsigned long);
 extern int ccw_device_clear(struct ccw_device *, unsigned long);
+int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
+                           unsigned long intparm, u8 lpm, u8 key);
+int ccw_device_tm_start_key(struct ccw_device *, struct tcw *,
+                           unsigned long, u8, u8);
+int ccw_device_tm_start_timeout_key(struct ccw_device *, struct tcw *,
+                           unsigned long, u8, u8, int);
+int ccw_device_tm_start(struct ccw_device *, struct tcw *,
+                           unsigned long, u8);
+int ccw_device_tm_start_timeout(struct ccw_device *, struct tcw *,
+                           unsigned long, u8, int);
+int ccw_device_tm_intrg(struct ccw_device *cdev);
 
 extern int ccw_device_set_online(struct ccw_device *cdev);
 extern int ccw_device_set_offline(struct ccw_device *cdev);
index b203336fd892596b7422a8506bb822044574dda7..606844d0a5c34c84af18863a204c21d4e157e4d3 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <linux/string.h>
 #include <asm/types.h>
-#include <asm/cio.h>
 
 #define __MAX_CHPID 255
 
@@ -41,6 +40,9 @@ static inline void chp_id_next(struct chp_id *chpid)
        }
 }
 
+#ifdef __KERNEL__
+#include <asm/cio.h>
+
 static inline int chp_id_is_valid(struct chp_id *chpid)
 {
        return (chpid->cssid <= __MAX_CSSID);
@@ -49,5 +51,6 @@ static inline int chp_id_is_valid(struct chp_id *chpid)
 
 #define chp_id_for_each(c) \
        for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c))
+#endif /* __KERNEL */
 
 #endif /* _ASM_S390_CHPID_H */
diff --git a/include/asm-s390/chsc.h b/include/asm-s390/chsc.h
new file mode 100644 (file)
index 0000000..d38d0cf
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * ioctl interface for /dev/chsc
+ *
+ * Copyright 2008 IBM Corp.
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ */
+
+#ifndef _ASM_CHSC_H
+#define _ASM_CHSC_H
+
+#include <asm/chpid.h>
+#include <asm/schid.h>
+
+struct chsc_async_header {
+       __u16 length;
+       __u16 code;
+       __u32 cmd_dependend;
+       __u32 key : 4;
+       __u32 : 28;
+       struct subchannel_id sid;
+} __attribute__ ((packed));
+
+struct chsc_async_area {
+       struct chsc_async_header header;
+       __u8 data[PAGE_SIZE - 16 /* size of chsc_async_header */];
+} __attribute__ ((packed));
+
+
+struct chsc_response_struct {
+       __u16 length;
+       __u16 code;
+       __u32 parms;
+       __u8 data[PAGE_SIZE - 8];
+} __attribute__ ((packed));
+
+struct chsc_chp_cd {
+       struct chp_id chpid;
+       int m;
+       int fmt;
+       struct chsc_response_struct cpcb;
+};
+
+struct chsc_cu_cd {
+       __u16 cun;
+       __u8 cssid;
+       int m;
+       int fmt;
+       struct chsc_response_struct cucb;
+};
+
+struct chsc_sch_cud {
+       struct subchannel_id schid;
+       int fmt;
+       struct chsc_response_struct scub;
+};
+
+struct conf_id {
+       int m;
+       __u8 cssid;
+       __u8 ssid;
+};
+
+struct chsc_conf_info {
+       struct conf_id id;
+       int fmt;
+       struct chsc_response_struct scid;
+};
+
+struct ccl_parm_chpid {
+       int m;
+       struct chp_id chp;
+};
+
+struct ccl_parm_cssids {
+       __u8 f_cssid;
+       __u8 l_cssid;
+};
+
+struct chsc_comp_list {
+       struct {
+               enum {
+                       CCL_CU_ON_CHP = 1,
+                       CCL_CHP_TYPE_CAP = 2,
+                       CCL_CSS_IMG = 4,
+                       CCL_CSS_IMG_CONF_CHAR = 5,
+                       CCL_IOP_CHP = 6,
+               } ctype;
+               int fmt;
+               struct ccl_parm_chpid chpid;
+               struct ccl_parm_cssids cssids;
+       } req;
+       struct chsc_response_struct sccl;
+};
+
+struct chsc_dcal {
+       struct {
+               enum {
+                       DCAL_CSS_IID_PN = 4,
+               } atype;
+               __u32 list_parm[2];
+               int fmt;
+       } req;
+       struct chsc_response_struct sdcal;
+};
+
+struct chsc_cpd_info {
+       struct chp_id chpid;
+       int m;
+       int fmt;
+       int rfmt;
+       int c;
+       struct chsc_response_struct chpdb;
+};
+
+#define CHSC_IOCTL_MAGIC 'c'
+
+#define CHSC_START _IOWR(CHSC_IOCTL_MAGIC, 0x81, struct chsc_async_area)
+#define CHSC_INFO_CHANNEL_PATH _IOWR(CHSC_IOCTL_MAGIC, 0x82, \
+                                   struct chsc_chp_cd)
+#define CHSC_INFO_CU _IOWR(CHSC_IOCTL_MAGIC, 0x83, struct chsc_cu_cd)
+#define CHSC_INFO_SCH_CU _IOWR(CHSC_IOCTL_MAGIC, 0x84, struct chsc_sch_cud)
+#define CHSC_INFO_CI _IOWR(CHSC_IOCTL_MAGIC, 0x85, struct chsc_conf_info)
+#define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list)
+#define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info)
+#define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal)
+
+#endif
index 0818ecd30ca6d1b84536ac16ae87fc0f9fee6bcb..6dccb071aec3df5158f84b4b4d1afce3ce5cd354 100644 (file)
@@ -16,7 +16,7 @@
 #define __MAX_CSSID 0
 
 /**
- * struct scsw - subchannel status word
+ * struct cmd_scsw - command-mode subchannel status word
  * @key: subchannel key
  * @sctl: suspend control
  * @eswf: esw format
@@ -38,7 +38,7 @@
  * @cstat: subchannel status
  * @count: residual count
  */
-struct scsw {
+struct cmd_scsw {
        __u32 key  : 4;
        __u32 sctl : 1;
        __u32 eswf : 1;
@@ -61,6 +61,114 @@ struct scsw {
        __u32 count : 16;
 } __attribute__ ((packed));
 
+/**
+ * struct tm_scsw - transport-mode subchannel status word
+ * @key: subchannel key
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @fmt: format
+ * @x: IRB-format control
+ * @q: interrogate-complete
+ * @ectl: extended control
+ * @pno: path not operational
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @tcw: TCW address
+ * @dstat: device status
+ * @cstat: subchannel status
+ * @fcxs: FCX status
+ * @schxs: subchannel-extended status
+ */
+struct tm_scsw {
+       u32 key:4;
+       u32 :1;
+       u32 eswf:1;
+       u32 cc:2;
+       u32 fmt:3;
+       u32 x:1;
+       u32 q:1;
+       u32 :1;
+       u32 ectl:1;
+       u32 pno:1;
+       u32 :1;
+       u32 fctl:3;
+       u32 actl:7;
+       u32 stctl:5;
+       u32 tcw;
+       u32 dstat:8;
+       u32 cstat:8;
+       u32 fcxs:8;
+       u32 schxs:8;
+} __attribute__ ((packed));
+
+/**
+ * union scsw - subchannel status word
+ * @cmd: command-mode SCSW
+ * @tm: transport-mode SCSW
+ */
+union scsw {
+       struct cmd_scsw cmd;
+       struct tm_scsw tm;
+} __attribute__ ((packed));
+
+int scsw_is_tm(union scsw *scsw);
+u32 scsw_key(union scsw *scsw);
+u32 scsw_eswf(union scsw *scsw);
+u32 scsw_cc(union scsw *scsw);
+u32 scsw_ectl(union scsw *scsw);
+u32 scsw_pno(union scsw *scsw);
+u32 scsw_fctl(union scsw *scsw);
+u32 scsw_actl(union scsw *scsw);
+u32 scsw_stctl(union scsw *scsw);
+u32 scsw_dstat(union scsw *scsw);
+u32 scsw_cstat(union scsw *scsw);
+int scsw_is_solicited(union scsw *scsw);
+int scsw_is_valid_key(union scsw *scsw);
+int scsw_is_valid_eswf(union scsw *scsw);
+int scsw_is_valid_cc(union scsw *scsw);
+int scsw_is_valid_ectl(union scsw *scsw);
+int scsw_is_valid_pno(union scsw *scsw);
+int scsw_is_valid_fctl(union scsw *scsw);
+int scsw_is_valid_actl(union scsw *scsw);
+int scsw_is_valid_stctl(union scsw *scsw);
+int scsw_is_valid_dstat(union scsw *scsw);
+int scsw_is_valid_cstat(union scsw *scsw);
+int scsw_cmd_is_valid_key(union scsw *scsw);
+int scsw_cmd_is_valid_sctl(union scsw *scsw);
+int scsw_cmd_is_valid_eswf(union scsw *scsw);
+int scsw_cmd_is_valid_cc(union scsw *scsw);
+int scsw_cmd_is_valid_fmt(union scsw *scsw);
+int scsw_cmd_is_valid_pfch(union scsw *scsw);
+int scsw_cmd_is_valid_isic(union scsw *scsw);
+int scsw_cmd_is_valid_alcc(union scsw *scsw);
+int scsw_cmd_is_valid_ssi(union scsw *scsw);
+int scsw_cmd_is_valid_zcc(union scsw *scsw);
+int scsw_cmd_is_valid_ectl(union scsw *scsw);
+int scsw_cmd_is_valid_pno(union scsw *scsw);
+int scsw_cmd_is_valid_fctl(union scsw *scsw);
+int scsw_cmd_is_valid_actl(union scsw *scsw);
+int scsw_cmd_is_valid_stctl(union scsw *scsw);
+int scsw_cmd_is_valid_dstat(union scsw *scsw);
+int scsw_cmd_is_valid_cstat(union scsw *scsw);
+int scsw_cmd_is_solicited(union scsw *scsw);
+int scsw_tm_is_valid_key(union scsw *scsw);
+int scsw_tm_is_valid_eswf(union scsw *scsw);
+int scsw_tm_is_valid_cc(union scsw *scsw);
+int scsw_tm_is_valid_fmt(union scsw *scsw);
+int scsw_tm_is_valid_x(union scsw *scsw);
+int scsw_tm_is_valid_q(union scsw *scsw);
+int scsw_tm_is_valid_ectl(union scsw *scsw);
+int scsw_tm_is_valid_pno(union scsw *scsw);
+int scsw_tm_is_valid_fctl(union scsw *scsw);
+int scsw_tm_is_valid_actl(union scsw *scsw);
+int scsw_tm_is_valid_stctl(union scsw *scsw);
+int scsw_tm_is_valid_dstat(union scsw *scsw);
+int scsw_tm_is_valid_cstat(union scsw *scsw);
+int scsw_tm_is_valid_fcxs(union scsw *scsw);
+int scsw_tm_is_valid_schxs(union scsw *scsw);
+int scsw_tm_is_solicited(union scsw *scsw);
+
 #define SCSW_FCTL_CLEAR_FUNC    0x1
 #define SCSW_FCTL_HALT_FUNC     0x2
 #define SCSW_FCTL_START_FUNC    0x4
@@ -303,7 +411,7 @@ struct esw3 {
  * if applicable).
  */
 struct irb {
-       struct scsw scsw;
+       union scsw scsw;
        union {
                struct esw0 esw0;
                struct esw1 esw1;
index b3ac262c4582f94738376cfcefff762cd50a26b1..3cad56923815156107862b27e69bb4b2648b5ad8 100644 (file)
 typedef s390_fp_regs elf_fpregset_t;
 typedef s390_regs elf_gregset_t;
 
+typedef s390_fp_regs compat_elf_fpregset_t;
+typedef s390_compat_regs compat_elf_gregset_t;
+
 #include <linux/sched.h>       /* for task_struct */
 #include <asm/system.h>                /* for save_access_regs */
 #include <asm/mmu_context.h>
@@ -123,6 +126,10 @@ typedef s390_regs elf_gregset_t;
 #define elf_check_arch(x) \
        (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
          && (x)->e_ident[EI_CLASS] == ELF_CLASS) 
+#define compat_elf_check_arch(x) \
+       (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
+        && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+#define compat_start_thread    start_thread31
 
 /* For SVR4/S390 the function pointer to be registered with `atexit` is
    passed in R14. */
@@ -131,6 +138,7 @@ typedef s390_regs elf_gregset_t;
                _r->gprs[14] = 0; \
        } while (0)
 
+#define CORE_DUMP_USE_REGSET
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
@@ -140,44 +148,6 @@ typedef s390_regs elf_gregset_t;
    that it will "exec", and that there is sufficient room for the brk.  */
 #define ELF_ET_DYN_BASE                (STACK_TOP / 3 * 2)
 
-/* Wow, the "main" arch needs arch dependent functions too.. :) */
-
-/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
-   now struct_user_regs, they are different) */
-
-static inline int dump_regs(struct pt_regs *ptregs, elf_gregset_t *regs)
-{
-       memcpy(&regs->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs));
-       save_access_regs(regs->acrs);
-       regs->orig_gpr2 = ptregs->orig_gpr2;
-       return 1;
-}
-
-#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs(regs, &pr_reg);
-
-static inline int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
-{
-       struct pt_regs *ptregs = task_pt_regs(tsk);
-       memcpy(&regs->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs));
-       memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
-       regs->orig_gpr2 = ptregs->orig_gpr2;
-       return 1;
-}
-
-#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs(tsk, regs)
-
-static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
-{
-       if (tsk == current)
-               save_fp_regs(fpregs);
-       else
-               memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
-       return 1;
-}
-
-#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
-
-
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports. */
 
@@ -204,7 +174,10 @@ do {                                                       \
                set_personality(PER_SVR4);              \
        else if (current->personality != PER_LINUX32)   \
                set_personality(PER_LINUX);             \
-       clear_thread_flag(TIF_31BIT);                   \
+       if ((ex).e_ident[EI_CLASS] == ELFCLASS32)       \
+               set_thread_flag(TIF_31BIT);             \
+       else                                            \
+               clear_thread_flag(TIF_31BIT);           \
 } while (0)
 #endif /* __s390x__ */
 
index b498f19bb9a70c2db83b2f755c0739cff757110a..80ef58c619709b9d7a576772f64339041a734b06 100644 (file)
@@ -122,7 +122,7 @@ struct etr_aib {
 } __attribute__ ((packed,aligned(8)));
 
 /* ETR interruption parameter */
-struct etr_interruption_parameter {
+struct etr_irq_parm {
        unsigned int _pad0      : 8;
        unsigned int pc0        : 1;    /* port 0 state change */
        unsigned int pc1        : 1;    /* port 1 state change */
@@ -213,7 +213,46 @@ static inline int etr_ptff(void *ptff_block, unsigned int func)
 #define ETR_PTFF_SGS   0x43    /* set gross steering rate */
 
 /* Functions needed by the machine check handler */
-extern void etr_switch_to_local(void);
-extern void etr_sync_check(void);
+void etr_switch_to_local(void);
+void etr_sync_check(void);
+
+/* STP interruption parameter */
+struct stp_irq_parm {
+       unsigned int _pad0      : 14;
+       unsigned int tsc        : 1;    /* Timing status change */
+       unsigned int lac        : 1;    /* Link availability change */
+       unsigned int tcpc       : 1;    /* Time control parameter change */
+       unsigned int _pad2      : 15;
+} __attribute__ ((packed));
+
+#define STP_OP_SYNC    1
+#define STP_OP_CTRL    3
+
+struct stp_sstpi {
+       unsigned int rsvd0;
+       unsigned int rsvd1 : 8;
+       unsigned int stratum : 8;
+       unsigned int vbits : 16;
+       unsigned int leaps : 16;
+       unsigned int tmd : 4;
+       unsigned int ctn : 4;
+       unsigned int rsvd2 : 3;
+       unsigned int c : 1;
+       unsigned int tst : 4;
+       unsigned int tzo : 16;
+       unsigned int dsto : 16;
+       unsigned int ctrl : 16;
+       unsigned int rsvd3 : 16;
+       unsigned int tto;
+       unsigned int rsvd4;
+       unsigned int ctnid[3];
+       unsigned int rsvd5;
+       unsigned int todoff[4];
+       unsigned int rsvd6[48];
+} __attribute__ ((packed));
+
+/* Functions needed by the machine check handler */
+void stp_sync_check(void);
+void stp_island_check(void);
 
 #endif /* __S390_ETR_H */
diff --git a/include/asm-s390/fcx.h b/include/asm-s390/fcx.h
new file mode 100644 (file)
index 0000000..8be1f3a
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ *  Functions for assembling fcx enabled I/O control blocks.
+ *
+ *    Copyright IBM Corp. 2008
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_FCX_H
+#define _ASM_S390_FCX_H _ASM_S390_FCX_H
+
+#include <linux/types.h>
+
+#define TCW_FORMAT_DEFAULT             0
+#define TCW_TIDAW_FORMAT_DEFAULT       0
+#define TCW_FLAGS_INPUT_TIDA           1 << (23 - 5)
+#define TCW_FLAGS_TCCB_TIDA            1 << (23 - 6)
+#define TCW_FLAGS_OUTPUT_TIDA          1 << (23 - 7)
+#define TCW_FLAGS_TIDAW_FORMAT(x)      ((x) & 3) << (23 - 9)
+#define TCW_FLAGS_GET_TIDAW_FORMAT(x)  (((x) >> (23 - 9)) & 3)
+
+/**
+ * struct tcw - Transport Control Word (TCW)
+ * @format: TCW format
+ * @flags: TCW flags
+ * @tccbl: Transport-Command-Control-Block Length
+ * @r: Read Operations
+ * @w: Write Operations
+ * @output: Output-Data Address
+ * @input: Input-Data Address
+ * @tsb: Transport-Status-Block Address
+ * @tccb: Transport-Command-Control-Block Address
+ * @output_count: Output Count
+ * @input_count: Input Count
+ * @intrg: Interrogate TCW Address
+ */
+struct tcw {
+       u32 format:2;
+       u32 :6;
+       u32 flags:24;
+       u32 :8;
+       u32 tccbl:6;
+       u32 r:1;
+       u32 w:1;
+       u32 :16;
+       u64 output;
+       u64 input;
+       u64 tsb;
+       u64 tccb;
+       u32 output_count;
+       u32 input_count;
+       u32 :32;
+       u32 :32;
+       u32 :32;
+       u32 intrg;
+} __attribute__ ((packed, aligned(64)));
+
+#define TIDAW_FLAGS_LAST               1 << (7 - 0)
+#define TIDAW_FLAGS_SKIP               1 << (7 - 1)
+#define TIDAW_FLAGS_DATA_INT           1 << (7 - 2)
+#define TIDAW_FLAGS_TTIC               1 << (7 - 3)
+#define TIDAW_FLAGS_INSERT_CBC         1 << (7 - 4)
+
+/**
+ * struct tidaw - Transport-Indirect-Addressing Word (TIDAW)
+ * @flags: TIDAW flags. Can be an arithmetic OR of the following constants:
+ * %TIDAW_FLAGS_LAST, %TIDAW_FLAGS_SKIP, %TIDAW_FLAGS_DATA_INT,
+ * %TIDAW_FLAGS_TTIC, %TIDAW_FLAGS_INSERT_CBC
+ * @count: Count
+ * @addr: Address
+ */
+struct tidaw {
+       u32 flags:8;
+       u32 :24;
+       u32 count;
+       u64 addr;
+} __attribute__ ((packed, aligned(16)));
+
+/**
+ * struct tsa_iostat - I/O-Status Transport-Status Area (IO-Stat TSA)
+ * @dev_time: Device Time
+ * @def_time: Defer Time
+ * @queue_time: Queue Time
+ * @dev_busy_time: Device-Busy Time
+ * @dev_act_time: Device-Active-Only Time
+ * @sense: Sense Data (if present)
+ */
+struct tsa_iostat {
+       u32 dev_time;
+       u32 def_time;
+       u32 queue_time;
+       u32 dev_busy_time;
+       u32 dev_act_time;
+       u8 sense[32];
+} __attribute__ ((packed));
+
+/**
+ * struct tsa_ddpcs - Device-Detected-Program-Check Transport-Status Area (DDPC TSA)
+ * @rc: Reason Code
+ * @rcq: Reason Code Qualifier
+ * @sense: Sense Data (if present)
+ */
+struct tsa_ddpc {
+       u32 :24;
+       u32 rc:8;
+       u8 rcq[16];
+       u8 sense[32];
+} __attribute__ ((packed));
+
+#define TSA_INTRG_FLAGS_CU_STATE_VALID         1 << (7 - 0)
+#define TSA_INTRG_FLAGS_DEV_STATE_VALID                1 << (7 - 1)
+#define TSA_INTRG_FLAGS_OP_STATE_VALID         1 << (7 - 2)
+
+/**
+ * struct tsa_intrg - Interrogate Transport-Status Area (Intrg. TSA)
+ * @format: Format
+ * @flags: Flags. Can be an arithmetic OR of the following constants:
+ * %TSA_INTRG_FLAGS_CU_STATE_VALID, %TSA_INTRG_FLAGS_DEV_STATE_VALID,
+ * %TSA_INTRG_FLAGS_OP_STATE_VALID
+ * @cu_state: Controle-Unit State
+ * @dev_state: Device State
+ * @op_state: Operation State
+ * @sd_info: State-Dependent Information
+ * @dl_id: Device-Level Identifier
+ * @dd_data: Device-Dependent Data
+ */
+struct tsa_intrg {
+       u32 format:8;
+       u32 flags:8;
+       u32 cu_state:8;
+       u32 dev_state:8;
+       u32 op_state:8;
+       u32 :24;
+       u8 sd_info[12];
+       u32 dl_id;
+       u8 dd_data[28];
+} __attribute__ ((packed));
+
+#define TSB_FORMAT_NONE                0
+#define TSB_FORMAT_IOSTAT      1
+#define TSB_FORMAT_DDPC                2
+#define TSB_FORMAT_INTRG       3
+
+#define TSB_FLAGS_DCW_OFFSET_VALID     1 << (7 - 0)
+#define TSB_FLAGS_COUNT_VALID          1 << (7 - 1)
+#define TSB_FLAGS_CACHE_MISS           1 << (7 - 2)
+#define TSB_FLAGS_TIME_VALID           1 << (7 - 3)
+#define TSB_FLAGS_FORMAT(x)            ((x) & 7)
+#define TSB_FORMAT(t)                  ((t)->flags & 7)
+
+/**
+ * struct tsb - Transport-Status Block (TSB)
+ * @length: Length
+ * @flags: Flags. Can be an arithmetic OR of the following constants:
+ * %TSB_FLAGS_DCW_OFFSET_VALID, %TSB_FLAGS_COUNT_VALID, %TSB_FLAGS_CACHE_MISS,
+ * %TSB_FLAGS_TIME_VALID
+ * @dcw_offset: DCW Offset
+ * @count: Count
+ * @tsa: Transport-Status-Area
+ */
+struct tsb {
+       u32 length:8;
+       u32 flags:8;
+       u32 dcw_offset:16;
+       u32 count;
+       u32 :32;
+       union {
+               struct tsa_iostat iostat;
+               struct tsa_ddpc ddpc;
+               struct tsa_intrg intrg;
+       } __attribute__ ((packed)) tsa;
+} __attribute__ ((packed, aligned(8)));
+
+#define DCW_INTRG_FORMAT_DEFAULT       0
+
+#define DCW_INTRG_RC_UNSPECIFIED       0
+#define DCW_INTRG_RC_TIMEOUT           1
+
+#define DCW_INTRG_RCQ_UNSPECIFIED      0
+#define DCW_INTRG_RCQ_PRIMARY          1
+#define DCW_INTRG_RCQ_SECONDARY                2
+
+#define DCW_INTRG_FLAGS_MPM            1 < (7 - 0)
+#define DCW_INTRG_FLAGS_PPR            1 < (7 - 1)
+#define DCW_INTRG_FLAGS_CRIT           1 < (7 - 2)
+
+/**
+ * struct dcw_intrg_data - Interrogate DCW data
+ * @format: Format. Should be %DCW_INTRG_FORMAT_DEFAULT
+ * @rc: Reason Code. Can be one of %DCW_INTRG_RC_UNSPECIFIED,
+ * %DCW_INTRG_RC_TIMEOUT
+ * @rcq: Reason Code Qualifier: Can be one of %DCW_INTRG_RCQ_UNSPECIFIED,
+ * %DCW_INTRG_RCQ_PRIMARY, %DCW_INTRG_RCQ_SECONDARY
+ * @lpm: Logical-Path Mask
+ * @pam: Path-Available Mask
+ * @pim: Path-Installed Mask
+ * @timeout: Timeout
+ * @flags: Flags. Can be an arithmetic OR of %DCW_INTRG_FLAGS_MPM,
+ * %DCW_INTRG_FLAGS_PPR, %DCW_INTRG_FLAGS_CRIT
+ * @time: Time
+ * @prog_id: Program Identifier
+ * @prog_data: Program-Dependent Data
+ */
+struct dcw_intrg_data {
+       u32 format:8;
+       u32 rc:8;
+       u32 rcq:8;
+       u32 lpm:8;
+       u32 pam:8;
+       u32 pim:8;
+       u32 timeout:16;
+       u32 flags:8;
+       u32 :24;
+       u32 :32;
+       u64 time;
+       u64 prog_id;
+       u8  prog_data[0];
+} __attribute__ ((packed));
+
+#define DCW_FLAGS_CC           1 << (7 - 1)
+
+#define DCW_CMD_WRITE          0x01
+#define DCW_CMD_READ           0x02
+#define DCW_CMD_CONTROL                0x03
+#define DCW_CMD_SENSE          0x04
+#define DCW_CMD_SENSE_ID       0xe4
+#define DCW_CMD_INTRG          0x40
+
+/**
+ * struct dcw - Device-Command Word (DCW)
+ * @cmd: Command Code. Can be one of %DCW_CMD_WRITE, %DCW_CMD_READ,
+ * %DCW_CMD_CONTROL, %DCW_CMD_SENSE, %DCW_CMD_SENSE_ID, %DCW_CMD_INTRG
+ * @flags: Flags. Can be an arithmetic OR of %DCW_FLAGS_CC
+ * @cd_count: Control-Data Count
+ * @count: Count
+ * @cd: Control Data
+ */
+struct dcw {
+       u32 cmd:8;
+       u32 flags:8;
+       u32 :8;
+       u32 cd_count:8;
+       u32 count;
+       u8 cd[0];
+} __attribute__ ((packed));
+
+#define TCCB_FORMAT_DEFAULT    0x7f
+#define TCCB_MAX_DCW           30
+#define TCCB_MAX_SIZE          (sizeof(struct tccb_tcah) + \
+                                TCCB_MAX_DCW * sizeof(struct dcw) + \
+                                sizeof(struct tccb_tcat))
+#define TCCB_SAC_DEFAULT       0xf901
+#define TCCB_SAC_INTRG         0xf902
+
+/**
+ * struct tccb_tcah - Transport-Command-Area Header (TCAH)
+ * @format: Format. Should be %TCCB_FORMAT_DEFAULT
+ * @tcal: Transport-Command-Area Length
+ * @sac: Service-Action Code. Can be one of %TCCB_SAC_DEFAULT, %TCCB_SAC_INTRG
+ * @prio: Priority
+ */
+struct tccb_tcah {
+       u32 format:8;
+       u32 :24;
+       u32 :24;
+       u32 tcal:8;
+       u32 sac:16;
+       u32 :8;
+       u32 prio:8;
+       u32 :32;
+} __attribute__ ((packed));
+
+/**
+ * struct tccb_tcat - Transport-Command-Area Trailer (TCAT)
+ * @count: Transport Count
+ */
+struct tccb_tcat {
+       u32 :32;
+       u32 count;
+} __attribute__ ((packed));
+
+/**
+ * struct tccb - (partial) Transport-Command-Control Block (TCCB)
+ * @tcah: TCAH
+ * @tca: Transport-Command Area
+ */
+struct tccb {
+       struct tccb_tcah tcah;
+       u8 tca[0];
+} __attribute__ ((packed, aligned(8)));
+
+struct tcw *tcw_get_intrg(struct tcw *tcw);
+void *tcw_get_data(struct tcw *tcw);
+struct tccb *tcw_get_tccb(struct tcw *tcw);
+struct tsb *tcw_get_tsb(struct tcw *tcw);
+
+void tcw_init(struct tcw *tcw, int r, int w);
+void tcw_finalize(struct tcw *tcw, int num_tidaws);
+
+void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw);
+void tcw_set_data(struct tcw *tcw, void *data, int use_tidal);
+void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb);
+void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb);
+
+void tccb_init(struct tccb *tccb, size_t tccb_size, u32 sac);
+void tsb_init(struct tsb *tsb);
+struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags,
+                        void *cd, u8 cd_count, u32 count);
+struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
+                           void *addr, u32 count);
+
+#endif /* _ASM_S390_FCX_H */
index c1b2e50392bb095dcba90a0b797133eb4583e2c1..eaca6dff5405f9d9dd6b6b3d8f359c77d2f09890 100644 (file)
@@ -56,15 +56,19 @@ struct ipl_block_fcp {
        u8  scp_data[];
 } __attribute__((packed));
 
+#define DIAG308_VMPARM_SIZE    64
+
 struct ipl_block_ccw {
-       u8  load_param[8];
+       u8  load_parm[8];
        u8  reserved1[84];
        u8  reserved2[2];
        u16 devno;
        u8  vm_flags;
        u8  reserved3[3];
        u32 vm_parm_len;
-       u8  reserved4[80];
+       u8  nss_name[8];
+       u8  vm_parm[DIAG308_VMPARM_SIZE];
+       u8  reserved4[8];
 } __attribute__((packed));
 
 struct ipl_parameter_block {
@@ -73,7 +77,7 @@ struct ipl_parameter_block {
                struct ipl_block_fcp fcp;
                struct ipl_block_ccw ccw;
        } ipl_info;
-} __attribute__((packed));
+} __attribute__((packed,aligned(4096)));
 
 /*
  * IPL validity flags
@@ -86,6 +90,8 @@ extern void do_reipl(void);
 extern void do_halt(void);
 extern void do_poff(void);
 extern void ipl_save_parameters(void);
+extern void ipl_update_parameters(void);
+extern void get_ipl_vmparm(char *);
 
 enum {
        IPL_DEVNO_VALID         = 1,
@@ -147,6 +153,11 @@ enum diag308_flags {
        DIAG308_FLAGS_LP_VALID  = 0x80,
 };
 
+enum diag308_vm_flags {
+       DIAG308_VM_FLAGS_NSS_VALID      = 0x80,
+       DIAG308_VM_FLAGS_VP_VALID       = 0x40,
+};
+
 enum diag308_rc {
        DIAG308_RC_OK   = 1,
 };
diff --git a/include/asm-s390/isc.h b/include/asm-s390/isc.h
new file mode 100644 (file)
index 0000000..34bb891
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _ASM_S390_ISC_H
+#define _ASM_S390_ISC_H
+
+#include <linux/types.h>
+
+/*
+ * I/O interruption subclasses used by drivers.
+ * Please add all used iscs here so that it is possible to distribute
+ * isc usage between drivers.
+ * Reminder: 0 is highest priority, 7 lowest.
+ */
+#define MAX_ISC 7
+
+/* Regular I/O interrupts. */
+#define IO_SCH_ISC 3                   /* regular I/O subchannels */
+#define CONSOLE_ISC 1                  /* console I/O subchannel */
+#define CHSC_SCH_ISC 7                 /* CHSC subchannels */
+/* Adapter interrupts. */
+#define QDIO_AIRQ_ISC IO_SCH_ISC       /* I/O subchannel in qdio mode */
+
+/* Functions for registration of I/O interruption subclasses */
+void isc_register(unsigned int isc);
+void isc_unregister(unsigned int isc);
+
+#endif /* _ASM_S390_ISC_H */
diff --git a/include/asm-s390/itcw.h b/include/asm-s390/itcw.h
new file mode 100644 (file)
index 0000000..a9bc5c3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  Functions for incremental construction of fcx enabled I/O control blocks.
+ *
+ *    Copyright IBM Corp. 2008
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_ITCW_H
+#define _ASM_S390_ITCW_H _ASM_S390_ITCW_H
+
+#include <linux/types.h>
+#include <asm/fcx.h>
+
+#define ITCW_OP_READ   0
+#define ITCW_OP_WRITE  1
+
+struct itcw;
+
+struct tcw *itcw_get_tcw(struct itcw *itcw);
+size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws);
+struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
+                      int max_tidaws, int intrg_max_tidaws);
+struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd,
+                        u8 cd_count, u32 count);
+struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr,
+                            u32 count);
+void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal);
+void itcw_finalize(struct itcw *itcw);
+
+#endif /* _ASM_S390_ITCW_H */
index bd0ea191dfa9d17030f89e5f2115407e56140dc8..0bdb704ae051f2bf1d83371702aa52bb7994d286 100644 (file)
@@ -29,6 +29,7 @@
  * the S390 page table tree.
  */
 #ifndef __ASSEMBLY__
+#include <linux/sched.h>
 #include <linux/mm_types.h>
 #include <asm/bitops.h>
 #include <asm/bug.h>
index a00f79dd323b540ae31fe01c0e764f7e012f157c..4af80af2a88f8c84ef5af5e2e94145b7537ff377 100644 (file)
@@ -143,11 +143,19 @@ struct stack_frame {
 /*
  * Do necessary setup to start up a new thread.
  */
-#define start_thread(regs, new_psw, new_stackp) do {            \
+#define start_thread(regs, new_psw, new_stackp) do {           \
        set_fs(USER_DS);                                        \
        regs->psw.mask  = psw_user_bits;                        \
-        regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
-        regs->gprs[15]  = new_stackp ;                          \
+       regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
+       regs->gprs[15]  = new_stackp;                           \
+} while (0)
+
+#define start_thread31(regs, new_psw, new_stackp) do {         \
+       set_fs(USER_DS);                                        \
+       regs->psw.mask  = psw_user32_bits;                      \
+       regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
+       regs->gprs[15]  = new_stackp;                           \
+       crst_table_downgrade(current->mm, 1UL << 31);           \
 } while (0)
 
 /* Forward declaration, a strange C thing */
@@ -328,16 +336,6 @@ extern void (*s390_base_mcck_handler_fn)(void);
 extern void (*s390_base_pgm_handler_fn)(void);
 extern void (*s390_base_ext_handler_fn)(void);
 
-/*
- * CPU idle notifier chain.
- */
-#define S390_CPU_IDLE          0
-#define S390_CPU_NOT_IDLE      1
-
-struct notifier_block;
-int register_idle_notifier(struct notifier_block *nb);
-int unregister_idle_notifier(struct notifier_block *nb);
-
 #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL
 
 #endif
index d7d4e2eb3e6f327b8528387d2f1a3822fc8820c6..af2c9ac28a07945eee89ddc0e7fc2e3d592fd25b 100644 (file)
@@ -215,6 +215,12 @@ typedef struct
         unsigned long addr;
 } __attribute__ ((aligned(8))) psw_t;
 
+typedef struct
+{
+       __u32   mask;
+       __u32   addr;
+} __attribute__ ((aligned(8))) psw_compat_t;
+
 #ifndef __s390x__
 
 #define PSW_MASK_PER           0x40000000UL
@@ -292,6 +298,15 @@ typedef struct
        unsigned long orig_gpr2;
 } s390_regs;
 
+typedef struct
+{
+       psw_compat_t    psw;
+       __u32           gprs[NUM_GPRS];
+       __u32           acrs[NUM_ACRS];
+       __u32           orig_gpr2;
+} s390_compat_regs;
+
+
 #ifdef __KERNEL__
 #include <asm/setup.h>
 #include <asm/page.h>
similarity index 65%
rename from drivers/s390/cio/schid.h
rename to include/asm-s390/schid.h
index 54328fec5adea77dab793ff8fbdbd636e0710714..5017ffa78e049f17caa116490789f68f9594ff7d 100644 (file)
@@ -1,12 +1,14 @@
-#ifndef S390_SCHID_H
-#define S390_SCHID_H
+#ifndef ASM_SCHID_H
+#define ASM_SCHID_H
 
 struct subchannel_id {
-       __u32 reserved:13;
-       __u32 ssid:2;
-       __u32 one:1;
-       __u32 sch_no:16;
-} __attribute__ ((packed,aligned(4)));
+       __u32 cssid : 8;
+       __u32 : 4;
+       __u32 m : 1;
+       __u32 ssid : 2;
+       __u32 one : 1;
+       __u32 sch_no : 16;
+} __attribute__ ((packed, aligned(4)));
 
 
 /* Helper function for sane state of pre-allocated subchannel_id. */
@@ -23,4 +25,4 @@ schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2)
        return !memcmp(schid1, schid2, sizeof(struct subchannel_id));
 }
 
-#endif /* S390_SCHID_H */
+#endif /* ASM_SCHID_H */
index b5f2843013a346902741fe2cfa8031ff4f3e8ea7..fed7bee650a06868072ef323723d7e6abe2336d7 100644 (file)
@@ -45,9 +45,9 @@ struct sclp_cpu_info {
 int sclp_get_cpu_info(struct sclp_cpu_info *info);
 int sclp_cpu_configure(u8 cpu);
 int sclp_cpu_deconfigure(u8 cpu);
-void sclp_read_info_early(void);
 void sclp_facilities_detect(void);
-unsigned long long sclp_memory_detect(void);
+unsigned long long sclp_get_rnmax(void);
+unsigned long long sclp_get_rzm(void);
 int sclp_sdias_blk_count(void);
 int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
 int sclp_chp_configure(struct chp_id chpid);
index ba69674012a7bf3b622b51d9c873bd6149bab131..f09ee3f729778dee8be898577303dbe4b988abc7 100644 (file)
@@ -8,14 +8,16 @@
 #ifndef _ASM_S390_SETUP_H
 #define _ASM_S390_SETUP_H
 
-#define COMMAND_LINE_SIZE      896
+#define COMMAND_LINE_SIZE      1024
+
+#define ARCH_COMMAND_LINE_SIZE 896
 
 #ifdef __KERNEL__
 
 #include <asm/types.h>
 
 #define PARMAREA               0x10400
-#define MEMORY_CHUNKS          16      /* max 0x7fff */
+#define MEMORY_CHUNKS          256
 
 #ifndef __ASSEMBLY__
 
 struct mem_chunk {
        unsigned long addr;
        unsigned long size;
-       unsigned long type;
+       int type;
 };
 
 extern struct mem_chunk memory_chunk[];
 extern unsigned long real_memory_size;
 
+void detect_memory_layout(struct mem_chunk chunk[]);
+
 #ifdef CONFIG_S390_SWITCH_AMODE
 extern unsigned int switch_amode;
 #else
@@ -61,7 +65,6 @@ extern unsigned long machine_flags;
 
 #define MACHINE_FLAG_VM                (1UL << 0)
 #define MACHINE_FLAG_IEEE      (1UL << 1)
-#define MACHINE_FLAG_P390      (1UL << 2)
 #define MACHINE_FLAG_CSP       (1UL << 3)
 #define MACHINE_FLAG_MVPG      (1UL << 4)
 #define MACHINE_FLAG_DIAG44    (1UL << 5)
@@ -97,7 +100,6 @@ extern unsigned long machine_flags;
 #define MACHINE_HAS_PFMF       (machine_flags & MACHINE_FLAG_PFMF)
 #endif /* __s390x__ */
 
-#define MACHINE_HAS_SCLP       (!MACHINE_IS_P390)
 #define ZFCPDUMP_HSA_SIZE      (32UL<<20)
 
 /*
index 06dfdab6c0e8412a305c1e2bbfba03354dd30176..545d219e6a2d0d4e5dec734d7dc1d55f2906dd72 100644 (file)
@@ -1,15 +1,15 @@
 #ifndef _ASM_S390_SPARSEMEM_H
 #define _ASM_S390_SPARSEMEM_H
 
-#define SECTION_SIZE_BITS      25
-
 #ifdef CONFIG_64BIT
 
+#define SECTION_SIZE_BITS      28
 #define MAX_PHYSADDR_BITS      42
 #define MAX_PHYSMEM_BITS       42
 
 #else
 
+#define SECTION_SIZE_BITS      25
 #define MAX_PHYSADDR_BITS      31
 #define MAX_PHYSMEM_BITS       31
 
index adb34860a543e42abc6b73ddcaf71b04dbbaf76b..d98d79e35cd6f6d6459110b6a0290e5fe59721d4 100644 (file)
@@ -48,6 +48,18 @@ extern int del_virt_timer(struct vtimer_list *timer);
 extern void init_cpu_vtimer(void);
 extern void vtime_init(void);
 
+#ifdef CONFIG_VIRT_TIMER
+
+extern void vtime_start_cpu_timer(void);
+extern void vtime_stop_cpu_timer(void);
+
+#else
+
+static inline void vtime_start_cpu_timer(void) { }
+static inline void vtime_stop_cpu_timer(void) { }
+
+#endif /* CONFIG_VIRT_TIMER */
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_S390_TIMER_H */
index f228f1b86877feabca366cb1db8a8dec1930b6d6..00d3bbd44117fe2093abe6dfca8ec6d6bb3e93cf 100644 (file)
@@ -29,7 +29,7 @@
 
 #define ZCRYPT_VERSION 2
 #define ZCRYPT_RELEASE 1
-#define ZCRYPT_VARIANT 0
+#define ZCRYPT_VARIANT 1
 
 #include <linux/ioctl.h>
 #include <linux/compiler.h>
index 14411c9de46f8f1f22434759c91b4ad892d17227..635d764dc13e346e26dc6f27b8a45d5701a9c55b 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/numa.h>
 #include <asm/processor.h>
 #include <asm/mmu.h>
+#include <asm/mpspec.h>
 
 #define COMPILER_DEPENDENT_INT64   long long
 #define COMPILER_DEPENDENT_UINT64  unsigned long long
@@ -160,9 +161,7 @@ struct bootnode;
 #ifdef CONFIG_ACPI_NUMA
 extern int acpi_numa;
 extern int acpi_scan_nodes(unsigned long start, unsigned long end);
-#ifdef CONFIG_X86_64
-# define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
-#endif
+#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
 extern void acpi_fake_nodes(const struct bootnode *fake_nodes,
                                   int num_nodes);
 #else
diff --git a/include/asm-x86/amd_iommu.h b/include/asm-x86/amd_iommu.h
new file mode 100644 (file)
index 0000000..30a1204
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
+ * Author: Joerg Roedel <joerg.roedel@amd.com>
+ *         Leo Duran <leo.duran@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _ASM_X86_AMD_IOMMU_H
+#define _ASM_X86_AMD_IOMMU_H
+
+#ifdef CONFIG_AMD_IOMMU
+extern int amd_iommu_init(void);
+extern int amd_iommu_init_dma_ops(void);
+extern void amd_iommu_detect(void);
+#else
+static inline int amd_iommu_init(void) { return -ENODEV; }
+static inline void amd_iommu_detect(void) { }
+#endif
+
+#endif
diff --git a/include/asm-x86/amd_iommu_types.h b/include/asm-x86/amd_iommu_types.h
new file mode 100644 (file)
index 0000000..7bfcb47
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
+ * Author: Joerg Roedel <joerg.roedel@amd.com>
+ *         Leo Duran <leo.duran@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __AMD_IOMMU_TYPES_H__
+#define __AMD_IOMMU_TYPES_H__
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+/*
+ * some size calculation constants
+ */
+#define DEV_TABLE_ENTRY_SIZE           256
+#define ALIAS_TABLE_ENTRY_SIZE         2
+#define RLOOKUP_TABLE_ENTRY_SIZE       (sizeof(void *))
+
+/* helper macros */
+#define LOW_U32(x) ((x) & ((1ULL << 32)-1))
+#define HIGH_U32(x) (LOW_U32((x) >> 32))
+
+/* Length of the MMIO region for the AMD IOMMU */
+#define MMIO_REGION_LENGTH       0x4000
+
+/* Capability offsets used by the driver */
+#define MMIO_CAP_HDR_OFFSET    0x00
+#define MMIO_RANGE_OFFSET      0x0c
+
+/* Masks, shifts and macros to parse the device range capability */
+#define MMIO_RANGE_LD_MASK     0xff000000
+#define MMIO_RANGE_FD_MASK     0x00ff0000
+#define MMIO_RANGE_BUS_MASK    0x0000ff00
+#define MMIO_RANGE_LD_SHIFT    24
+#define MMIO_RANGE_FD_SHIFT    16
+#define MMIO_RANGE_BUS_SHIFT   8
+#define MMIO_GET_LD(x)  (((x) & MMIO_RANGE_LD_MASK) >> MMIO_RANGE_LD_SHIFT)
+#define MMIO_GET_FD(x)  (((x) & MMIO_RANGE_FD_MASK) >> MMIO_RANGE_FD_SHIFT)
+#define MMIO_GET_BUS(x) (((x) & MMIO_RANGE_BUS_MASK) >> MMIO_RANGE_BUS_SHIFT)
+
+/* Flag masks for the AMD IOMMU exclusion range */
+#define MMIO_EXCL_ENABLE_MASK 0x01ULL
+#define MMIO_EXCL_ALLOW_MASK  0x02ULL
+
+/* Used offsets into the MMIO space */
+#define MMIO_DEV_TABLE_OFFSET   0x0000
+#define MMIO_CMD_BUF_OFFSET     0x0008
+#define MMIO_EVT_BUF_OFFSET     0x0010
+#define MMIO_CONTROL_OFFSET     0x0018
+#define MMIO_EXCL_BASE_OFFSET   0x0020
+#define MMIO_EXCL_LIMIT_OFFSET  0x0028
+#define MMIO_CMD_HEAD_OFFSET   0x2000
+#define MMIO_CMD_TAIL_OFFSET   0x2008
+#define MMIO_EVT_HEAD_OFFSET   0x2010
+#define MMIO_EVT_TAIL_OFFSET   0x2018
+#define MMIO_STATUS_OFFSET     0x2020
+
+/* feature control bits */
+#define CONTROL_IOMMU_EN        0x00ULL
+#define CONTROL_HT_TUN_EN       0x01ULL
+#define CONTROL_EVT_LOG_EN      0x02ULL
+#define CONTROL_EVT_INT_EN      0x03ULL
+#define CONTROL_COMWAIT_EN      0x04ULL
+#define CONTROL_PASSPW_EN       0x08ULL
+#define CONTROL_RESPASSPW_EN    0x09ULL
+#define CONTROL_COHERENT_EN     0x0aULL
+#define CONTROL_ISOC_EN         0x0bULL
+#define CONTROL_CMDBUF_EN       0x0cULL
+#define CONTROL_PPFLOG_EN       0x0dULL
+#define CONTROL_PPFINT_EN       0x0eULL
+
+/* command specific defines */
+#define CMD_COMPL_WAIT          0x01
+#define CMD_INV_DEV_ENTRY       0x02
+#define CMD_INV_IOMMU_PAGES     0x03
+
+#define CMD_COMPL_WAIT_STORE_MASK      0x01
+#define CMD_INV_IOMMU_PAGES_SIZE_MASK  0x01
+#define CMD_INV_IOMMU_PAGES_PDE_MASK   0x02
+
+#define CMD_INV_IOMMU_ALL_PAGES_ADDRESS        0x7fffffffffffffffULL
+
+/* macros and definitions for device table entries */
+#define DEV_ENTRY_VALID         0x00
+#define DEV_ENTRY_TRANSLATION   0x01
+#define DEV_ENTRY_IR            0x3d
+#define DEV_ENTRY_IW            0x3e
+#define DEV_ENTRY_EX            0x67
+#define DEV_ENTRY_SYSMGT1       0x68
+#define DEV_ENTRY_SYSMGT2       0x69
+#define DEV_ENTRY_INIT_PASS     0xb8
+#define DEV_ENTRY_EINT_PASS     0xb9
+#define DEV_ENTRY_NMI_PASS      0xba
+#define DEV_ENTRY_LINT0_PASS    0xbe
+#define DEV_ENTRY_LINT1_PASS    0xbf
+
+/* constants to configure the command buffer */
+#define CMD_BUFFER_SIZE    8192
+#define CMD_BUFFER_ENTRIES 512
+#define MMIO_CMD_SIZE_SHIFT 56
+#define MMIO_CMD_SIZE_512 (0x9ULL << MMIO_CMD_SIZE_SHIFT)
+
+#define PAGE_MODE_1_LEVEL 0x01
+#define PAGE_MODE_2_LEVEL 0x02
+#define PAGE_MODE_3_LEVEL 0x03
+
+#define IOMMU_PDE_NL_0   0x000ULL
+#define IOMMU_PDE_NL_1   0x200ULL
+#define IOMMU_PDE_NL_2   0x400ULL
+#define IOMMU_PDE_NL_3   0x600ULL
+
+#define IOMMU_PTE_L2_INDEX(address) (((address) >> 30) & 0x1ffULL)
+#define IOMMU_PTE_L1_INDEX(address) (((address) >> 21) & 0x1ffULL)
+#define IOMMU_PTE_L0_INDEX(address) (((address) >> 12) & 0x1ffULL)
+
+#define IOMMU_MAP_SIZE_L1 (1ULL << 21)
+#define IOMMU_MAP_SIZE_L2 (1ULL << 30)
+#define IOMMU_MAP_SIZE_L3 (1ULL << 39)
+
+#define IOMMU_PTE_P  (1ULL << 0)
+#define IOMMU_PTE_U  (1ULL << 59)
+#define IOMMU_PTE_FC (1ULL << 60)
+#define IOMMU_PTE_IR (1ULL << 61)
+#define IOMMU_PTE_IW (1ULL << 62)
+
+#define IOMMU_L1_PDE(address) \
+       ((address) | IOMMU_PDE_NL_1 | IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW)
+#define IOMMU_L2_PDE(address) \
+       ((address) | IOMMU_PDE_NL_2 | IOMMU_PTE_P | IOMMU_PTE_IR | IOMMU_PTE_IW)
+
+#define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL)
+#define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_P)
+#define IOMMU_PTE_PAGE(pte) (phys_to_virt((pte) & IOMMU_PAGE_MASK))
+#define IOMMU_PTE_MODE(pte) (((pte) >> 9) & 0x07)
+
+#define IOMMU_PROT_MASK 0x03
+#define IOMMU_PROT_IR 0x01
+#define IOMMU_PROT_IW 0x02
+
+/* IOMMU capabilities */
+#define IOMMU_CAP_IOTLB   24
+#define IOMMU_CAP_NPCACHE 26
+
+#define MAX_DOMAIN_ID 65536
+
+struct protection_domain {
+       spinlock_t lock;
+       u16 id;
+       int mode;
+       u64 *pt_root;
+       void *priv;
+};
+
+struct dma_ops_domain {
+       struct list_head list;
+       struct protection_domain domain;
+       unsigned long aperture_size;
+       unsigned long next_bit;
+       unsigned long *bitmap;
+       u64 **pte_pages;
+};
+
+struct amd_iommu {
+       struct list_head list;
+       spinlock_t lock;
+
+       u16 devid;
+       u16 cap_ptr;
+
+       u64 mmio_phys;
+       u8 *mmio_base;
+       u32 cap;
+       u16 first_device;
+       u16 last_device;
+       u64 exclusion_start;
+       u64 exclusion_length;
+
+       u8 *cmd_buf;
+       u32 cmd_buf_size;
+
+       int need_sync;
+
+       struct dma_ops_domain *default_dom;
+};
+
+extern struct list_head amd_iommu_list;
+
+struct dev_table_entry {
+       u32 data[8];
+};
+
+struct unity_map_entry {
+       struct list_head list;
+       u16 devid_start;
+       u16 devid_end;
+       u64 address_start;
+       u64 address_end;
+       int prot;
+};
+
+extern struct list_head amd_iommu_unity_map;
+
+/* data structures for device handling */
+extern struct dev_table_entry *amd_iommu_dev_table;
+extern u16 *amd_iommu_alias_table;
+extern struct amd_iommu **amd_iommu_rlookup_table;
+
+extern unsigned amd_iommu_aperture_order;
+
+extern u16 amd_iommu_last_bdf;
+
+/* data structures for protection domain handling */
+extern struct protection_domain **amd_iommu_pd_table;
+extern unsigned long *amd_iommu_pd_alloc_bitmap;
+
+extern int amd_iommu_isolate;
+
+static inline void print_devid(u16 devid, int nl)
+{
+       int bus = devid >> 8;
+       int dev = devid >> 3 & 0x1f;
+       int fn  = devid & 0x07;
+
+       printk("%02x:%02x.%x", bus, dev, fn);
+       if (nl)
+               printk("\n");
+}
+
+#endif
index be9639a9a186244fef74318f901172415a7e9343..4e2c1e517f0652fb1877c378f760fdb03fe6e8bb 100644 (file)
@@ -36,15 +36,11 @@ extern void generic_apic_probe(void);
 #ifdef CONFIG_X86_LOCAL_APIC
 
 extern int apic_verbosity;
-extern int timer_over_8254;
 extern int local_apic_timer_c2_ok;
-extern int local_apic_timer_disabled;
 
-extern int apic_runs_main_timer;
 extern int ioapic_force;
-extern int disable_apic;
-extern int disable_apic_timer;
 
+extern int disable_apic;
 /*
  * Basic functions accessing APICs.
  */
@@ -125,16 +121,22 @@ extern void enable_NMI_through_LVT0(void);
  */
 #ifdef CONFIG_X86_64
 extern void early_init_lapic_mapping(void);
+extern int apic_is_clustered_box(void);
+#else
+static inline int apic_is_clustered_box(void)
+{
+       return 0;
+}
 #endif
 
 extern u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask);
 extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask);
 
-extern int apic_is_clustered_box(void);
 
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
 #define local_apic_timer_c2_ok         1
+static inline void init_apic_mappings(void) { }
 
 #endif /* !CONFIG_X86_LOCAL_APIC */
 
index 90dec0c236469455821607eca77a5a86684af6d2..97220321f39de383b4624533a7ae1969756fb0b6 100644 (file)
@@ -1,37 +1,40 @@
 #ifndef _ASM_X86_ASM_H
 #define _ASM_X86_ASM_H
 
-#ifdef CONFIG_X86_32
-/* 32 bits */
-
-# define _ASM_PTR      " .long "
-# define _ASM_ALIGN    " .balign 4 "
-# define _ASM_MOV_UL   " movl "
-
-# define _ASM_INC      " incl "
-# define _ASM_DEC      " decl "
-# define _ASM_ADD      " addl "
-# define _ASM_SUB      " subl "
-# define _ASM_XADD     " xaddl "
-
+#ifdef __ASSEMBLY__
+# define __ASM_FORM(x) x
+# define __ASM_EX_SEC  .section __ex_table
 #else
-/* 64 bits */
+# define __ASM_FORM(x) " " #x " "
+# define __ASM_EX_SEC  " .section __ex_table,\"a\"\n"
+#endif
 
-# define _ASM_PTR      " .quad "
-# define _ASM_ALIGN    " .balign 8 "
-# define _ASM_MOV_UL   " movq "
-
-# define _ASM_INC      " incq "
-# define _ASM_DEC      " decq "
-# define _ASM_ADD      " addq "
-# define _ASM_SUB      " subq "
-# define _ASM_XADD     " xaddq "
-
-#endif /* CONFIG_X86_32 */
+#ifdef CONFIG_X86_32
+# define __ASM_SEL(a,b) __ASM_FORM(a)
+#else
+# define __ASM_SEL(a,b) __ASM_FORM(b)
+#endif
+
+#define __ASM_SIZE(inst)       __ASM_SEL(inst##l, inst##q)
+#define __ASM_REG(reg)         __ASM_SEL(e##reg, r##reg)
+
+#define _ASM_PTR       __ASM_SEL(.long, .quad)
+#define _ASM_ALIGN     __ASM_SEL(.balign 4, .balign 8)
+#define _ASM_MOV_UL    __ASM_SIZE(mov)
+
+#define _ASM_INC       __ASM_SIZE(inc)
+#define _ASM_DEC       __ASM_SIZE(dec)
+#define _ASM_ADD       __ASM_SIZE(add)
+#define _ASM_SUB       __ASM_SIZE(sub)
+#define _ASM_XADD      __ASM_SIZE(xadd)
+#define _ASM_AX                __ASM_REG(ax)
+#define _ASM_BX                __ASM_REG(bx)
+#define _ASM_CX                __ASM_REG(cx)
+#define _ASM_DX                __ASM_REG(dx)
 
 /* Exception table entry */
 # define _ASM_EXTABLE(from,to) \
-       " .section __ex_table,\"a\"\n" \
+       __ASM_EX_SEC    \
        _ASM_ALIGN "\n" \
        _ASM_PTR #from "," #to "\n" \
        " .previous\n"
index 3e0cd7d3833569bab88b4e7414201aafa0d0dab2..a0095191c02e92f319c13b2d3bc27fcd2f1fbc70 100644 (file)
  * resource counting etc..
  */
 
-#ifdef CONFIG_SMP
-#define LOCK "lock ; "
-#else
-#define LOCK ""
-#endif
-
 /*
  * Make sure gcc doesn't try to be clever and move things around
  * on us. We need to use _exactly_ the address the user gave us,
@@ -431,6 +425,32 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
        return c != (u);
 }
 
+/**
+ * atomic_inc_short - increment of a short integer
+ * @v: pointer to type int
+ *
+ * Atomically adds 1 to @v
+ * Returns the new value of @u
+ */
+static inline short int atomic_inc_short(short int *v)
+{
+       asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
+       return *v;
+}
+
+/**
+ * atomic_or_long - OR of two long integers
+ * @v1: pointer to type unsigned long
+ * @v2: pointer to type unsigned long
+ *
+ * Atomically ORs @v1 and @v2
+ * Returns the result of the OR
+ */
+static inline void atomic_or_long(unsigned long *v1, unsigned long v2)
+{
+       asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2));
+}
+
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
 /* These are x86-specific, used by some header files */
index b4a46b7be7941fca2a7cd8636d9701bbf9ed7aa4..0033e50c13b28cec6bfcd479ced48e01798e9e76 100644 (file)
@@ -14,4 +14,6 @@ static inline unsigned int get_bios_ebda(void)
        return address; /* 0 means none */
 }
 
+void reserve_ebda_region(void);
+
 #endif /* _MACH_BIOS_EBDA_H */
index ee4b3ead6a438d8d68c626803031072f60a19060..96b1829cea15aa0fbc00177e394a9bab47a5a5b7 100644 (file)
 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
 /* Technically wrong, but this avoids compilation errors on some gcc
    versions. */
-#define ADDR "=m" (*(volatile long *) addr)
+#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
 #else
-#define ADDR "+m" (*(volatile long *) addr)
+#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
 #endif
 
+#define ADDR                           BITOP_ADDR(addr)
+
+/*
+ * We do the locked ops that don't return the old value as
+ * a mask operation on a byte.
+ */
+#define IS_IMMEDIATE(nr)               (__builtin_constant_p(nr))
+#define CONST_MASK_ADDR(nr, addr)      BITOP_ADDR((void *)(addr) + ((nr)>>3))
+#define CONST_MASK(nr)                 (1 << ((nr) & 7))
+
 /**
  * set_bit - Atomically set a bit in memory
  * @nr: the bit to set
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void set_bit(int nr, volatile void *addr)
+static inline void set_bit(unsigned int nr, volatile unsigned long *addr)
 {
-       asm volatile(LOCK_PREFIX "bts %1,%0" : ADDR : "Ir" (nr) : "memory");
+       if (IS_IMMEDIATE(nr)) {
+               asm volatile(LOCK_PREFIX "orb %1,%0"
+                       : CONST_MASK_ADDR(nr, addr)
+                       : "iq" ((u8)CONST_MASK(nr))
+                       : "memory");
+       } else {
+               asm volatile(LOCK_PREFIX "bts %1,%0"
+                       : BITOP_ADDR(addr) : "Ir" (nr) : "memory");
+       }
 }
 
 /**
@@ -57,7 +75,7 @@ static inline void set_bit(int nr, volatile void *addr)
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static inline void __set_bit(int nr, volatile void *addr)
+static inline void __set_bit(int nr, volatile unsigned long *addr)
 {
        asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
 }
@@ -72,9 +90,17 @@ static inline void __set_bit(int nr, volatile void *addr)
  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  * in order to ensure changes are visible on other processors.
  */
-static inline void clear_bit(int nr, volatile void *addr)
+static inline void clear_bit(int nr, volatile unsigned long *addr)
 {
-       asm volatile(LOCK_PREFIX "btr %1,%0" : ADDR : "Ir" (nr));
+       if (IS_IMMEDIATE(nr)) {
+               asm volatile(LOCK_PREFIX "andb %1,%0"
+                       : CONST_MASK_ADDR(nr, addr)
+                       : "iq" ((u8)~CONST_MASK(nr)));
+       } else {
+               asm volatile(LOCK_PREFIX "btr %1,%0"
+                       : BITOP_ADDR(addr)
+                       : "Ir" (nr));
+       }
 }
 
 /*
@@ -85,13 +111,13 @@ static inline void clear_bit(int nr, volatile void *addr)
  * clear_bit() is atomic and implies release semantics before the memory
  * operation. It can be used for an unlock.
  */
-static inline void clear_bit_unlock(unsigned nr, volatile void *addr)
+static inline void clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
 {
        barrier();
        clear_bit(nr, addr);
 }
 
-static inline void __clear_bit(int nr, volatile void *addr)
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
 {
        asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
 }
@@ -108,7 +134,7 @@ static inline void __clear_bit(int nr, volatile void *addr)
  * No memory barrier is required here, because x86 cannot reorder stores past
  * older loads. Same principle as spin_unlock.
  */
-static inline void __clear_bit_unlock(unsigned nr, volatile void *addr)
+static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
 {
        barrier();
        __clear_bit(nr, addr);
@@ -126,7 +152,7 @@ static inline void __clear_bit_unlock(unsigned nr, volatile void *addr)
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static inline void __change_bit(int nr, volatile void *addr)
+static inline void __change_bit(int nr, volatile unsigned long *addr)
 {
        asm volatile("btc %1,%0" : ADDR : "Ir" (nr));
 }
@@ -140,7 +166,7 @@ static inline void __change_bit(int nr, volatile void *addr)
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void change_bit(int nr, volatile void *addr)
+static inline void change_bit(int nr, volatile unsigned long *addr)
 {
        asm volatile(LOCK_PREFIX "btc %1,%0" : ADDR : "Ir" (nr));
 }
@@ -153,7 +179,7 @@ static inline void change_bit(int nr, volatile void *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_set_bit(int nr, volatile void *addr)
+static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -170,7 +196,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
  *
  * This is the same as test_and_set_bit on x86.
  */
-static inline int test_and_set_bit_lock(int nr, volatile void *addr)
+static inline int test_and_set_bit_lock(int nr, volatile unsigned long *addr)
 {
        return test_and_set_bit(nr, addr);
 }
@@ -184,7 +210,7 @@ static inline int test_and_set_bit_lock(int nr, volatile void *addr)
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
-static inline int __test_and_set_bit(int nr, volatile void *addr)
+static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -203,7 +229,7 @@ static inline int __test_and_set_bit(int nr, volatile void *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_clear_bit(int nr, volatile void *addr)
+static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -223,7 +249,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr)
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
-static inline int __test_and_clear_bit(int nr, volatile void *addr)
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -235,7 +261,7 @@ static inline int __test_and_clear_bit(int nr, volatile void *addr)
 }
 
 /* WARNING: non atomic and it can be reordered! */
-static inline int __test_and_change_bit(int nr, volatile void *addr)
+static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -255,7 +281,7 @@ static inline int __test_and_change_bit(int nr, volatile void *addr)
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_change_bit(int nr, volatile void *addr)
+static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
 {
        int oldbit;
 
@@ -266,13 +292,13 @@ static inline int test_and_change_bit(int nr, volatile void *addr)
        return oldbit;
 }
 
-static inline int constant_test_bit(int nr, const volatile void *addr)
+static inline int constant_test_bit(int nr, const volatile unsigned long *addr)
 {
        return ((1UL << (nr % BITS_PER_LONG)) &
                (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
 }
 
-static inline int variable_test_bit(int nr, volatile const void *addr)
+static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
 {
        int oldbit;
 
index f62f4733606bfa9388ad98dce4a0c72fec7e9b2f..ae22bdf0ab14a74c4b9d01f91fb07230047e1cee 100644 (file)
@@ -11,6 +11,7 @@
 
 /* setup data types */
 #define SETUP_NONE                     0
+#define SETUP_E820_EXT                 1
 
 /* extensible setup data list node */
 struct setup_data {
@@ -40,6 +41,7 @@ struct setup_header {
        __u8    type_of_loader;
        __u8    loadflags;
 #define LOADED_HIGH    (1<<0)
+#define QUIET_FLAG     (1<<5)
 #define KEEP_SEGMENTS  (1<<6)
 #define CAN_USE_HEAP   (1<<7)
        __u16   setup_move_size;
index d9b26b9a28cf9f0e3f64f4206f1922b331408f54..17463ccf816618b59a144ec76f57e51589e8866c 100644 (file)
@@ -93,6 +93,39 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
        return old;
 }
 
+/*
+ * Always use locked operations when touching memory shared with a
+ * hypervisor, since the system may be SMP even if the guest kernel
+ * isn't.
+ */
+static inline unsigned long __sync_cmpxchg(volatile void *ptr,
+                                          unsigned long old,
+                                          unsigned long new, int size)
+{
+       unsigned long prev;
+       switch (size) {
+       case 1:
+               asm volatile("lock; cmpxchgb %b1,%2"
+                            : "=a"(prev)
+                            : "q"(new), "m"(*__xg(ptr)), "0"(old)
+                            : "memory");
+               return prev;
+       case 2:
+               asm volatile("lock; cmpxchgw %w1,%2"
+                            : "=a"(prev)
+                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
+                            : "memory");
+               return prev;
+       case 4:
+               asm volatile("lock; cmpxchgl %1,%2"
+                            : "=a"(prev)
+                            : "r"(new), "m"(*__xg(ptr)), "0"(old)
+                            : "memory");
+               return prev;
+       }
+       return old;
+}
+
 static inline unsigned long __cmpxchg_local(volatile void *ptr,
                                            unsigned long old,
                                            unsigned long new, int size)
@@ -139,6 +172,10 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
        ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
                                             (unsigned long)(n),        \
                                             sizeof(*(ptr))))
+#define sync_cmpxchg(ptr, o, n)                                                \
+       ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o),  \
+                                           (unsigned long)(n),         \
+                                           sizeof(*(ptr))))
 #define cmpxchg64_local(ptr, o, n)                                     \
 ({                                                                     \
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
index 0d609c837a41575fe8ce75cd4140f2efa99554cb..75ef959db32921922db8f38bac44f8ac960cbc4a 100644 (file)
@@ -74,8 +74,8 @@
 #define X86_FEATURE_ARCH_PERFMON (3*32+11) /* Intel Architectural PerfMon */
 #define X86_FEATURE_PEBS       (3*32+12)  /* Precise-Event Based Sampling */
 #define X86_FEATURE_BTS                (3*32+13)  /* Branch Trace Store */
-/* 14 free */
-/* 15 free */
+#define X86_FEATURE_SYSCALL32  (3*32+14)  /* syscall in ia32 userspace */
+#define X86_FEATURE_SYSENTER32 (3*32+15)  /* sysenter in ia32 userspace */
 #define X86_FEATURE_REP_GOOD   (3*32+16) /* rep microcode works well on this CPU */
 #define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
 #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
 /* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
 #define X86_FEATURE_LAHF_LM    (6*32+ 0) /* LAHF/SAHF in long mode */
 #define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
+#define X86_FEATURE_IBS                (6*32+ 10) /* Instruction Based Sampling */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
@@ -142,11 +143,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, cleared_cpu_caps);         \
+       set_bit(bit, (unsigned long *)cleared_cpu_caps); \
 } while (0)
 #define setup_force_cpu_cap(bit) do { \
        set_cpu_cap(&boot_cpu_data, bit);       \
-       clear_bit(bit, cleared_cpu_caps);       \
+       clear_bit(bit, (unsigned long *)cleared_cpu_caps);      \
 } while (0)
 
 #define cpu_has_fpu            boot_cpu_has(X86_FEATURE_FPU)
index d2526d3f7346884a9efc19bb2cef085595aefffa..7515c19d498884d770e901740eb506d5f96c4807 100644 (file)
@@ -1,5 +1,39 @@
+#ifndef _X86_CURRENT_H
+#define _X86_CURRENT_H
+
 #ifdef CONFIG_X86_32
-# include "current_32.h"
-#else
-# include "current_64.h"
-#endif
+#include <linux/compiler.h>
+#include <asm/percpu.h>
+
+struct task_struct;
+
+DECLARE_PER_CPU(struct task_struct *, current_task);
+static __always_inline struct task_struct *get_current(void)
+{
+       return x86_read_percpu(current_task);
+}
+
+#else /* X86_32 */
+
+#ifndef __ASSEMBLY__
+#include <asm/pda.h>
+
+struct task_struct;
+
+static __always_inline struct task_struct *get_current(void)
+{
+       return read_pda(pcurrent);
+}
+
+#else /* __ASSEMBLY__ */
+
+#include <asm/asm-offsets.h>
+#define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* X86_32 */
+
+#define current get_current()
+
+#endif /* X86_CURRENT_H */
diff --git a/include/asm-x86/current_32.h b/include/asm-x86/current_32.h
deleted file mode 100644 (file)
index 5af9bdb..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _I386_CURRENT_H
-#define _I386_CURRENT_H
-
-#include <linux/compiler.h>
-#include <asm/percpu.h>
-
-struct task_struct;
-
-DECLARE_PER_CPU(struct task_struct *, current_task);
-static __always_inline struct task_struct *get_current(void)
-{
-       return x86_read_percpu(current_task);
-}
-
-#define current get_current()
-
-#endif /* !(_I386_CURRENT_H) */
diff --git a/include/asm-x86/current_64.h b/include/asm-x86/current_64.h
deleted file mode 100644 (file)
index 2d368ed..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _X86_64_CURRENT_H
-#define _X86_64_CURRENT_H
-
-#if !defined(__ASSEMBLY__)
-struct task_struct;
-
-#include <asm/pda.h>
-
-static inline struct task_struct *get_current(void)
-{
-       struct task_struct *t = read_pda(pcurrent);
-       return t;
-}
-
-#define current get_current()
-
-#else
-
-#ifndef ASM_OFFSET_H
-#include <asm/asm-offsets.h>
-#endif
-
-#define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg
-
-#endif
-
-#endif /* !(_X86_64_CURRENT_H) */
index 28bddbcb38be7e3d27cd73fc0a725aef68a26ad0..a44c4dc705902c6b1e76c92d71f1c68f759a0df4 100644 (file)
@@ -29,11 +29,17 @@ static inline void fill_ldt(struct desc_struct *desc,
 extern struct desc_ptr idt_descr;
 extern gate_desc idt_table[];
 
+struct gdt_page {
+       struct desc_struct gdt[GDT_ENTRIES];
+} __attribute__((aligned(PAGE_SIZE)));
+DECLARE_PER_CPU(struct gdt_page, gdt_page);
+
+static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
+{
+       return per_cpu(gdt_page, cpu).gdt;
+}
+
 #ifdef CONFIG_X86_64
-extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
-extern struct desc_ptr cpu_gdt_descr[];
-/* the cpu gdt accessor */
-#define get_cpu_gdt_table(x) ((struct desc_struct *)cpu_gdt_descr[x].address)
 
 static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
                             unsigned dpl, unsigned ist, unsigned seg)
@@ -51,16 +57,6 @@ static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
 }
 
 #else
-struct gdt_page {
-       struct desc_struct gdt[GDT_ENTRIES];
-} __attribute__((aligned(PAGE_SIZE)));
-DECLARE_PER_CPU(struct gdt_page, gdt_page);
-
-static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
-{
-       return per_cpu(gdt_page, cpu).gdt;
-}
-
 static inline void pack_gate(gate_desc *gate, unsigned char type,
                             unsigned long base, unsigned dpl, unsigned flags,
                             unsigned short seg)
@@ -311,6 +307,28 @@ static inline void set_intr_gate(unsigned int n, void *addr)
        _set_gate(n, GATE_INTERRUPT, addr, 0, 0, __KERNEL_CS);
 }
 
+#define SYS_VECTOR_FREE                0
+#define SYS_VECTOR_ALLOCED     1
+
+extern int first_system_vector;
+extern char system_vectors[];
+
+static inline void alloc_system_vector(int vector)
+{
+       if (system_vectors[vector] == SYS_VECTOR_FREE) {
+               system_vectors[vector] = SYS_VECTOR_ALLOCED;
+               if (first_system_vector > vector)
+                       first_system_vector = vector;
+       } else
+               BUG();
+}
+
+static inline void alloc_intr_gate(unsigned int n, void *addr)
+{
+       alloc_system_vector(n);
+       set_intr_gate(n, addr);
+}
+
 /*
  * This routine sets up an interrupt gate at directory privilege level 3.
  */
index eccb4ea1f91850f26263fcc171e58509cb965dd0..f7bacf357daca2be4fb7345d75deb69c6c6c0ee3 100644 (file)
@@ -75,10 +75,14 @@ struct ldttss_desc64 {
 typedef struct gate_struct64 gate_desc;
 typedef struct ldttss_desc64 ldt_desc;
 typedef struct ldttss_desc64 tss_desc;
+#define gate_offset(g) ((g).offset_low | ((unsigned long)(g).offset_middle << 16) | ((unsigned long)(g).offset_high << 32))
+#define gate_segment(g) ((g).segment)
 #else
 typedef struct desc_struct gate_desc;
 typedef struct desc_struct ldt_desc;
 typedef struct desc_struct tss_desc;
+#define gate_offset(g)         (((g).b & 0xffff0000) | ((g).a & 0x0000ffff))
+#define gate_segment(g)                ((g).a >> 16)
 #endif
 
 struct desc_ptr {
index 4edf7514a75033d8173428e1ce1640995a87f154..58a86571fe0f8451df8800bd87b218e2be028886 100644 (file)
@@ -3,12 +3,6 @@
 
 #include <asm/io.h>
 
-#ifdef CONFIG_X86_32
-
-#define dmi_alloc alloc_bootmem
-
-#else /* CONFIG_X86_32 */
-
 #define DMI_MAX_DATA 2048
 
 extern int dmi_alloc_index;
@@ -25,8 +19,6 @@ static inline void *dmi_alloc(unsigned len)
        return dmi_alloc_data + idx;
 }
 
-#endif
-
 /* Use early IO mappings for DMI because it's initialized early */
 #define dmi_ioremap early_ioremap
 #define dmi_iounmap early_iounmap
index b3cbb0ccae18db9d0b08dca79af386349116422d..0bfe250894f77fe3db16afe332c75808626ae567 100644 (file)
@@ -1,5 +1,61 @@
-#ifdef CONFIG_X86_32
-# include "dwarf2_32.h"
+#ifndef _DWARF2_H
+#define _DWARF2_H
+
+#ifndef __ASSEMBLY__
+#warning "asm/dwarf2.h should be only included in pure assembly files"
+#endif
+
+/*
+   Macros for dwarf2 CFI unwind table entries.
+   See "as.info" for details on these pseudo ops. Unfortunately
+   they are only supported in very new binutils, so define them
+   away for older version.
+ */
+
+#ifdef CONFIG_AS_CFI
+
+#define CFI_STARTPROC .cfi_startproc
+#define CFI_ENDPROC .cfi_endproc
+#define CFI_DEF_CFA .cfi_def_cfa
+#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
+#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
+#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
+#define CFI_OFFSET .cfi_offset
+#define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_REGISTER .cfi_register
+#define CFI_RESTORE .cfi_restore
+#define CFI_REMEMBER_STATE .cfi_remember_state
+#define CFI_RESTORE_STATE .cfi_restore_state
+#define CFI_UNDEFINED .cfi_undefined
+
+#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
+#define CFI_SIGNAL_FRAME .cfi_signal_frame
+#else
+#define CFI_SIGNAL_FRAME
+#endif
+
 #else
-# include "dwarf2_64.h"
+
+/* Due to the structure of pre-exisiting code, don't use assembler line
+   comment character # to ignore the arguments. Instead, use a dummy macro. */
+.macro ignore a=0, b=0, c=0, d=0
+.endm
+
+#define CFI_STARTPROC  ignore
+#define CFI_ENDPROC    ignore
+#define CFI_DEF_CFA    ignore
+#define CFI_DEF_CFA_REGISTER   ignore
+#define CFI_DEF_CFA_OFFSET     ignore
+#define CFI_ADJUST_CFA_OFFSET  ignore
+#define CFI_OFFSET     ignore
+#define CFI_REL_OFFSET ignore
+#define CFI_REGISTER   ignore
+#define CFI_RESTORE    ignore
+#define CFI_REMEMBER_STATE ignore
+#define CFI_RESTORE_STATE ignore
+#define CFI_UNDEFINED ignore
+#define CFI_SIGNAL_FRAME ignore
+
+#endif
+
 #endif
diff --git a/include/asm-x86/dwarf2_32.h b/include/asm-x86/dwarf2_32.h
deleted file mode 100644 (file)
index 6d66398..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _DWARF2_H
-#define _DWARF2_H
-
-#ifndef __ASSEMBLY__
-#warning "asm/dwarf2.h should be only included in pure assembly files"
-#endif
-
-/*
-   Macros for dwarf2 CFI unwind table entries.
-   See "as.info" for details on these pseudo ops. Unfortunately
-   they are only supported in very new binutils, so define them
-   away for older version.
- */
-
-#ifdef CONFIG_UNWIND_INFO
-
-#define CFI_STARTPROC .cfi_startproc
-#define CFI_ENDPROC .cfi_endproc
-#define CFI_DEF_CFA .cfi_def_cfa
-#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
-#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
-#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
-#define CFI_OFFSET .cfi_offset
-#define CFI_REL_OFFSET .cfi_rel_offset
-#define CFI_REGISTER .cfi_register
-#define CFI_RESTORE .cfi_restore
-#define CFI_REMEMBER_STATE .cfi_remember_state
-#define CFI_RESTORE_STATE .cfi_restore_state
-#define CFI_UNDEFINED .cfi_undefined
-
-#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
-#define CFI_SIGNAL_FRAME .cfi_signal_frame
-#else
-#define CFI_SIGNAL_FRAME
-#endif
-
-#else
-
-/* Due to the structure of pre-exisiting code, don't use assembler line
-   comment character # to ignore the arguments. Instead, use a dummy macro. */
-.macro ignore a=0, b=0, c=0, d=0
-.endm
-
-#define CFI_STARTPROC  ignore
-#define CFI_ENDPROC    ignore
-#define CFI_DEF_CFA    ignore
-#define CFI_DEF_CFA_REGISTER   ignore
-#define CFI_DEF_CFA_OFFSET     ignore
-#define CFI_ADJUST_CFA_OFFSET  ignore
-#define CFI_OFFSET     ignore
-#define CFI_REL_OFFSET ignore
-#define CFI_REGISTER   ignore
-#define CFI_RESTORE    ignore
-#define CFI_REMEMBER_STATE ignore
-#define CFI_RESTORE_STATE ignore
-#define CFI_UNDEFINED ignore
-#define CFI_SIGNAL_FRAME ignore
-
-#endif
-
-#endif
diff --git a/include/asm-x86/dwarf2_64.h b/include/asm-x86/dwarf2_64.h
deleted file mode 100644 (file)
index c950519..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _DWARF2_H
-#define _DWARF2_H 1
-
-#ifndef __ASSEMBLY__
-#warning "asm/dwarf2.h should be only included in pure assembly files"
-#endif
-
-/*
-   Macros for dwarf2 CFI unwind table entries.
-   See "as.info" for details on these pseudo ops. Unfortunately
-   they are only supported in very new binutils, so define them
-   away for older version.
- */
-
-#ifdef CONFIG_AS_CFI
-
-#define CFI_STARTPROC .cfi_startproc
-#define CFI_ENDPROC .cfi_endproc
-#define CFI_DEF_CFA .cfi_def_cfa
-#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
-#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
-#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
-#define CFI_OFFSET .cfi_offset
-#define CFI_REL_OFFSET .cfi_rel_offset
-#define CFI_REGISTER .cfi_register
-#define CFI_RESTORE .cfi_restore
-#define CFI_REMEMBER_STATE .cfi_remember_state
-#define CFI_RESTORE_STATE .cfi_restore_state
-#define CFI_UNDEFINED .cfi_undefined
-#ifdef CONFIG_AS_CFI_SIGNAL_FRAME
-#define CFI_SIGNAL_FRAME .cfi_signal_frame
-#else
-#define CFI_SIGNAL_FRAME
-#endif
-
-#else
-
-/* use assembler line comment character # to ignore the arguments. */
-#define CFI_STARTPROC  #
-#define CFI_ENDPROC    #
-#define CFI_DEF_CFA    #
-#define CFI_DEF_CFA_REGISTER   #
-#define CFI_DEF_CFA_OFFSET     #
-#define CFI_ADJUST_CFA_OFFSET  #
-#define CFI_OFFSET     #
-#define CFI_REL_OFFSET #
-#define CFI_REGISTER   #
-#define CFI_RESTORE    #
-#define CFI_REMEMBER_STATE     #
-#define CFI_RESTORE_STATE      #
-#define CFI_UNDEFINED  #
-#define CFI_SIGNAL_FRAME       #
-
-#endif
-
-#endif
index 7004251fc66bd7925a787bd09ccb675dc0714de8..33e793e991d0caebe8b3fecc8104b0d4246942fd 100644 (file)
@@ -2,6 +2,41 @@
 #define __ASM_E820_H
 #define E820MAP        0x2d0           /* our map */
 #define E820MAX        128             /* number of entries in E820MAP */
+
+/*
+ * Legacy E820 BIOS limits us to 128 (E820MAX) nodes due to the
+ * constrained space in the zeropage.  If we have more nodes than
+ * that, and if we've booted off EFI firmware, then the EFI tables
+ * passed us from the EFI firmware can list more nodes.  Size our
+ * internal memory map tables to have room for these additional
+ * nodes, based on up to three entries per node for which the
+ * kernel was built: MAX_NUMNODES == (1 << CONFIG_NODES_SHIFT),
+ * plus E820MAX, allowing space for the possible duplicate E820
+ * entries that might need room in the same arrays, prior to the
+ * call to sanitize_e820_map() to remove duplicates.  The allowance
+ * of three memory map entries per node is "enough" entries for
+ * the initial hardware platform motivating this mechanism to make
+ * use of additional EFI map entries.  Future platforms may want
+ * to allow more than three entries per node or otherwise refine
+ * this size.
+ */
+
+/*
+ * Odd: 'make headers_check' complains about numa.h if I try
+ * to collapse the next two #ifdef lines to a single line:
+ *     #if defined(__KERNEL__) && defined(CONFIG_EFI)
+ */
+#ifdef __KERNEL__
+#ifdef CONFIG_EFI
+#include <linux/numa.h>
+#define E820_X_MAX (E820MAX + 3 * MAX_NUMNODES)
+#else  /* ! CONFIG_EFI */
+#define E820_X_MAX E820MAX
+#endif
+#else  /* ! __KERNEL__ */
+#define E820_X_MAX E820MAX
+#endif
+
 #define E820NR 0x1e8           /* # entries in E820MAP */
 
 #define E820_RAM       1
@@ -9,6 +44,9 @@
 #define E820_ACPI      3
 #define E820_NVS       4
 
+/* reserved RAM used by kernel itself */
+#define E820_RESERVED_KERN        128
+
 #ifndef __ASSEMBLY__
 struct e820entry {
        __u64 addr;     /* start of memory segment */
@@ -18,22 +56,79 @@ struct e820entry {
 
 struct e820map {
        __u32 nr_map;
-       struct e820entry map[E820MAX];
+       struct e820entry map[E820_X_MAX];
 };
+
+/* see comment in arch/x86/kernel/e820.c */
+extern struct e820map e820;
+extern struct e820map e820_saved;
+
+extern int e820_any_mapped(u64 start, u64 end, unsigned type);
+extern int e820_all_mapped(u64 start, u64 end, unsigned type);
+extern void e820_add_region(u64 start, u64 size, int type);
+extern void e820_print_map(char *who);
+extern int
+sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, int *pnr_map);
+extern u64 e820_update_range(u64 start, u64 size, unsigned old_type,
+                              unsigned new_type);
+extern u64 e820_remove_range(u64 start, u64 size, unsigned old_type,
+                            int checktype);
+extern void update_e820(void);
+extern void e820_setup_gap(void);
+extern int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
+                       unsigned long start_addr, unsigned long long end_addr);
+struct setup_data;
+extern void parse_e820_ext(struct setup_data *data, unsigned long pa_data);
+
+#if defined(CONFIG_X86_64) || \
+       (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))
+extern void e820_mark_nosave_regions(unsigned long limit_pfn);
+#else
+static inline void e820_mark_nosave_regions(unsigned long limit_pfn)
+{
+}
+#endif
+
+extern unsigned long end_user_pfn;
+
+extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
+extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
+extern void reserve_early(u64 start, u64 end, char *name);
+extern void reserve_early_overlap_ok(u64 start, u64 end, char *name);
+extern void free_early(u64 start, u64 end);
+extern void early_res_to_bootmem(u64 start, u64 end);
+extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
+
+extern unsigned long e820_end_of_ram_pfn(void);
+extern unsigned long e820_end_of_low_ram_pfn(void);
+extern int e820_find_active_region(const struct e820entry *ei,
+                                 unsigned long start_pfn,
+                                 unsigned long last_pfn,
+                                 unsigned long *ei_startpfn,
+                                 unsigned long *ei_endpfn);
+extern void e820_register_active_regions(int nid, unsigned long start_pfn,
+                                        unsigned long end_pfn);
+extern u64 e820_hole_size(u64 start, u64 end);
+extern void finish_e820_parsing(void);
+extern void e820_reserve_resources(void);
+extern void setup_memory_map(void);
+extern char *default_machine_specific_memory_setup(void);
+extern char *machine_specific_memory_setup(void);
+extern char *memory_setup(void);
+
 #endif /* __ASSEMBLY__ */
 
 #define ISA_START_ADDRESS      0xa0000
 #define ISA_END_ADDRESS                0x100000
+#define is_ISA_range(s, e) ((s) >= ISA_START_ADDRESS && (e) < ISA_END_ADDRESS)
 
 #define BIOS_BEGIN             0x000a0000
 #define BIOS_END               0x00100000
 
 #ifdef __KERNEL__
-#ifdef CONFIG_X86_32
-# include "e820_32.h"
-#else
-# include "e820_64.h"
-#endif
+#include <linux/ioport.h>
+
+#define HIGH_MEMORY    (1024*1024)
 #endif /* __KERNEL__ */
 
 #endif  /* __ASM_E820_H */
diff --git a/include/asm-x86/e820_32.h b/include/asm-x86/e820_32.h
deleted file mode 100644 (file)
index a9f7c6e..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * structures and definitions for the int 15, ax=e820 memory map
- * scheme.
- *
- * In a nutshell, arch/i386/boot/setup.S populates a scratch table
- * in the empty_zero_block that contains a list of usable address/size
- * duples.   In arch/i386/kernel/setup.c, this information is
- * transferred into the e820map, and in arch/i386/mm/init.c, that
- * new information is used to mark pages reserved or not.
- *
- */
-#ifndef __E820_HEADER
-#define __E820_HEADER
-
-#include <linux/ioport.h>
-
-#define HIGH_MEMORY    (1024*1024)
-
-#ifndef __ASSEMBLY__
-
-extern struct e820map e820;
-extern void update_e820(void);
-
-extern int e820_all_mapped(unsigned long start, unsigned long end,
-                          unsigned type);
-extern int e820_any_mapped(u64 start, u64 end, unsigned type);
-extern void propagate_e820_map(void);
-extern void register_bootmem_low_pages(unsigned long max_low_pfn);
-extern void add_memory_region(unsigned long long start,
-                             unsigned long long size, int type);
-extern void update_memory_range(u64 start, u64 size, unsigned old_type,
-                               unsigned new_type);
-extern void e820_register_memory(void);
-extern void limit_regions(unsigned long long size);
-extern void print_memory_map(char *who);
-extern void init_iomem_resources(struct resource *code_resource,
-                                struct resource *data_resource,
-                                struct resource *bss_resource);
-
-#if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION)
-extern void e820_mark_nosave_regions(void);
-#else
-static inline void e820_mark_nosave_regions(void)
-{
-}
-#endif
-
-
-#endif/*!__ASSEMBLY__*/
-#endif/*__E820_HEADER*/
diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h
deleted file mode 100644 (file)
index 71c4d68..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * structures and definitions for the int 15, ax=e820 memory map
- * scheme.
- *
- * In a nutshell, setup.S populates a scratch table in the
- * empty_zero_block that contains a list of usable address/size
- * duples.  setup.c, this information is transferred into the e820map,
- * and in init.c/numa.c, that new information is used to mark pages
- * reserved or not.
- */
-#ifndef __E820_HEADER
-#define __E820_HEADER
-
-#include <linux/ioport.h>
-
-#ifndef __ASSEMBLY__
-extern unsigned long find_e820_area(unsigned long start, unsigned long end,
-                                   unsigned long size, unsigned long align);
-extern unsigned long find_e820_area_size(unsigned long start,
-                                        unsigned long *sizep,
-                                        unsigned long align);
-extern void add_memory_region(unsigned long start, unsigned long size,
-                             int type);
-extern void update_memory_range(u64 start, u64 size, unsigned old_type,
-                               unsigned new_type);
-extern void setup_memory_region(void);
-extern void contig_e820_setup(void);
-extern unsigned long e820_end_of_ram(void);
-extern void e820_reserve_resources(void);
-extern void e820_mark_nosave_regions(void);
-extern int e820_any_mapped(unsigned long start, unsigned long end,
-                          unsigned type);
-extern int e820_all_mapped(unsigned long start, unsigned long end,
-                          unsigned type);
-extern int e820_any_non_reserved(unsigned long start, unsigned long end);
-extern int is_memory_any_valid(unsigned long start, unsigned long end);
-extern int e820_all_non_reserved(unsigned long start, unsigned long end);
-extern int is_memory_all_valid(unsigned long start, unsigned long end);
-extern unsigned long e820_hole_size(unsigned long start, unsigned long end);
-
-extern void e820_setup_gap(void);
-extern void e820_register_active_regions(int nid, unsigned long start_pfn,
-                                        unsigned long end_pfn);
-
-extern void finish_e820_parsing(void);
-
-extern struct e820map e820;
-extern void update_e820(void);
-
-extern void reserve_early(unsigned long start, unsigned long end, char *name);
-extern void free_early(unsigned long start, unsigned long end);
-extern void early_res_to_bootmem(unsigned long start, unsigned long end);
-
-#endif/*!__ASSEMBLY__*/
-
-#endif/*__E820_HEADER*/
index d53004b855cce82b6303cbe8adde1bf47d450977..7ed2bd7a7f51c3621b26acde91bdaa65f36d9f96 100644 (file)
@@ -90,7 +90,7 @@ extern void *efi_ioremap(unsigned long addr, unsigned long size);
 
 #endif /* CONFIG_X86_32 */
 
-extern void efi_reserve_bootmem(void);
+extern void efi_reserve_early(void);
 extern void efi_call_phys_prelog(void);
 extern void efi_call_phys_epilog(void);
 
index 8f232dc5b5fe09dc81274a5eb830ee352c052169..7be4733c793e58c404fbab54d3c34e2e05ff8aa0 100644 (file)
@@ -83,9 +83,9 @@ extern unsigned int vdso_enabled;
        (((x)->e_machine == EM_386) || ((x)->e_machine == EM_486))
 
 #include <asm/processor.h>
+#include <asm/system.h>
 
 #ifdef CONFIG_X86_32
-#include <asm/system.h>                /* for savesegment */
 #include <asm/desc.h>
 
 #define elf_check_arch(x)      elf_check_arch_ia32(x)
index 5bd206973dca3cf184b859a1c2031ce6d3501ff3..44d4f82173496d2984b9c6612c4d4fe48341a146 100644 (file)
@@ -7,7 +7,62 @@
 # include "fixmap_64.h"
 #endif
 
+extern int fixmaps_set;
+
+void __native_set_fixmap(enum fixed_addresses idx, pte_t pte);
+void native_set_fixmap(enum fixed_addresses idx,
+                      unsigned long phys, pgprot_t flags);
+
+#ifndef CONFIG_PARAVIRT
+static inline void __set_fixmap(enum fixed_addresses idx,
+                               unsigned long phys, pgprot_t flags)
+{
+       native_set_fixmap(idx, phys, flags);
+}
+#endif
+
+#define set_fixmap(idx, phys)                          \
+       __set_fixmap(idx, phys, PAGE_KERNEL)
+
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys)                  \
+       __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+
 #define clear_fixmap(idx)                      \
        __set_fixmap(idx, 0, __pgprot(0))
 
+#define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x)       ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without translation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+       /*
+        * this branch gets completely eliminated after inlining,
+        * except when someone tries to use fixaddr indices in an
+        * illegal way. (such as mixing up address types or using
+        * out-of-range indices).
+        *
+        * If it doesn't get removed, the linker will complain
+        * loudly with a reasonably clear error message..
+        */
+       if (idx >= __end_of_fixed_addresses)
+               __this_fixmap_does_not_exist();
+
+       return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+       BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+       return __virt_to_fix(vaddr);
+}
 #endif
index 4b96148e90c15587f715969f2ff4c6fd5a07d4d8..aae2f0501a4006a145ca82e9d65f7999c89aaf5f 100644 (file)
@@ -79,10 +79,6 @@ enum fixed_addresses {
        FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
        FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
-#ifdef CONFIG_ACPI
-       FIX_ACPI_BEGIN,
-       FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
-#endif
 #ifdef CONFIG_PCI_MMCONFIG
        FIX_PCIE_MCFG,
 #endif
@@ -103,23 +99,18 @@ enum fixed_addresses {
                        (__end_of_permanent_fixed_addresses & 511),
        FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
        FIX_WP_TEST,
+#ifdef CONFIG_ACPI
+       FIX_ACPI_BEGIN,
+       FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
+#endif
 #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
        FIX_OHCI1394_BASE,
 #endif
        __end_of_fixed_addresses
 };
 
-extern void __set_fixmap(enum fixed_addresses idx,
-                        unsigned long phys, pgprot_t flags);
 extern void reserve_top_address(unsigned long reserve);
 
-#define set_fixmap(idx, phys)                          \
-       __set_fixmap(idx, phys, PAGE_KERNEL)
-/*
- * Some hardware wants to get fixmapped without caching.
- */
-#define set_fixmap_nocache(idx, phys)                  \
-       __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
 
 #define FIXADDR_TOP    ((unsigned long)__FIXADDR_TOP)
 
@@ -128,38 +119,5 @@ extern void reserve_top_address(unsigned long reserve);
 #define FIXADDR_START          (FIXADDR_TOP - __FIXADDR_SIZE)
 #define FIXADDR_BOOT_START     (FIXADDR_TOP - __FIXADDR_BOOT_SIZE)
 
-#define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
-#define __virt_to_fix(x)       ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
-
-extern void __this_fixmap_does_not_exist(void);
-
-/*
- * 'index to address' translation. If anyone tries to use the idx
- * directly without tranlation, we catch the bug with a NULL-deference
- * kernel oops. Illegal ranges of incoming indices are caught too.
- */
-static __always_inline unsigned long fix_to_virt(const unsigned int idx)
-{
-       /*
-        * this branch gets completely eliminated after inlining,
-        * except when someone tries to use fixaddr indices in an
-        * illegal way. (such as mixing up address types or using
-        * out-of-range indices).
-        *
-        * If it doesn't get removed, the linker will complain
-        * loudly with a reasonably clear error message..
-        */
-       if (idx >= __end_of_fixed_addresses)
-               __this_fixmap_does_not_exist();
-
-       return __fix_to_virt(idx);
-}
-
-static inline unsigned long virt_to_fix(const unsigned long vaddr)
-{
-       BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
-       return __virt_to_fix(vaddr);
-}
-
 #endif /* !__ASSEMBLY__ */
 #endif
index 355d26a75a821a87aa298ee52f79617015dc7a8e..00f3d74a0524d71e77bfb4730a8b6c13f38b052f 100644 (file)
@@ -12,6 +12,7 @@
 #define _ASM_FIXMAP_64_H
 
 #include <linux/kernel.h>
+#include <asm/acpi.h>
 #include <asm/apicdef.h>
 #include <asm/page.h>
 #include <asm/vsyscall.h>
@@ -39,30 +40,38 @@ enum fixed_addresses {
        VSYSCALL_HPET,
        FIX_DBGP_BASE,
        FIX_EARLYCON_MEM_BASE,
-       FIX_HPET_BASE,
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
        FIX_IO_APIC_BASE_0,
        FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
        FIX_EFI_IO_MAP_LAST_PAGE,
        FIX_EFI_IO_MAP_FIRST_PAGE = FIX_EFI_IO_MAP_LAST_PAGE
                                  + MAX_EFI_IO_PAGES - 1,
+#ifdef CONFIG_PARAVIRT
+       FIX_PARAVIRT_BOOTMAP,
+#endif
+#ifdef CONFIG_ACPI
+       FIX_ACPI_BEGIN,
+       FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
+#endif
 #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
        FIX_OHCI1394_BASE,
 #endif
+       __end_of_permanent_fixed_addresses,
+       /*
+        * 256 temporary boot-time mappings, used by early_ioremap(),
+        * before ioremap() is functional.
+        *
+        * We round it up to the next 512 pages boundary so that we
+        * can have a single pgd entry and a single pte table:
+        */
+#define NR_FIX_BTMAPS          64
+#define FIX_BTMAPS_NESTING     4
+       FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 -
+                       (__end_of_permanent_fixed_addresses & 511),
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1,
        __end_of_fixed_addresses
 };
 
-extern void __set_fixmap(enum fixed_addresses idx,
-                        unsigned long phys, pgprot_t flags);
-
-#define set_fixmap(idx, phys)                  \
-       __set_fixmap(idx, phys, PAGE_KERNEL)
-/*
- * Some hardware wants to get fixmapped without caching.
- */
-#define set_fixmap_nocache(idx, phys)                  \
-       __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
-
 #define FIXADDR_TOP    (VSYSCALL_END-PAGE_SIZE)
 #define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
@@ -71,30 +80,4 @@ extern void __set_fixmap(enum fixed_addresses idx,
 #define FIXADDR_USER_START     ((unsigned long)VSYSCALL32_VSYSCALL)
 #define FIXADDR_USER_END       (FIXADDR_USER_START + PAGE_SIZE)
 
-#define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
-
-extern void __this_fixmap_does_not_exist(void);
-
-/*
- * 'index to address' translation. If anyone tries to use the idx
- * directly without translation, we catch the bug with a NULL-deference
- * kernel oops. Illegal ranges of incoming indices are caught too.
- */
-static __always_inline unsigned long fix_to_virt(const unsigned int idx)
-{
-       /*
-        * this branch gets completely eliminated after inlining,
-        * except when someone tries to use fixaddr indices in an
-        * illegal way. (such as mixing up address types or using
-        * out-of-range indices).
-        *
-        * If it doesn't get removed, the linker will complain
-        * loudly with a reasonably clear error message..
-        */
-       if (idx >= __end_of_fixed_addresses)
-               __this_fixmap_does_not_exist();
-
-       return __fix_to_virt(idx);
-}
-
 #endif
index 90958ed993faa3d140c495911bb77a1c57037ee9..33b9aeeb35a2367ba5deb1092622c579c6431c5a 100644 (file)
@@ -1,34 +1,72 @@
-#ifndef _ASM_X8664_IOMMU_H
-#define _ASM_X8664_IOMMU_H 1
-
-extern void pci_iommu_shutdown(void);
-extern void no_iommu_init(void);
-extern int force_iommu, no_iommu;
-extern int iommu_detected;
-#ifdef CONFIG_GART_IOMMU
-extern void gart_iommu_init(void);
-extern void gart_iommu_shutdown(void);
-extern void __init gart_parse_options(char *);
-extern void early_gart_iommu_check(void);
-extern void gart_iommu_hole_init(void);
+#ifndef _ASM_X8664_GART_H
+#define _ASM_X8664_GART_H 1
+
+#include <asm/e820.h>
+#include <asm/iommu.h>
+
+extern void set_up_gart_resume(u32, u32);
+
 extern int fallback_aper_order;
 extern int fallback_aper_force;
-extern int gart_iommu_aperture;
-extern int gart_iommu_aperture_allowed;
-extern int gart_iommu_aperture_disabled;
 extern int fix_aperture;
-#else
-#define gart_iommu_aperture 0
-#define gart_iommu_aperture_allowed 0
 
-static inline void early_gart_iommu_check(void)
+/* PTE bits. */
+#define GPTE_VALID     1
+#define GPTE_COHERENT  2
+
+/* Aperture control register bits. */
+#define GARTEN         (1<<0)
+#define DISGARTCPU     (1<<4)
+#define DISGARTIO      (1<<5)
+
+/* GART cache control register bits. */
+#define INVGART                (1<<0)
+#define GARTPTEERR     (1<<1)
+
+/* K8 On-cpu GART registers */
+#define AMD64_GARTAPERTURECTL  0x90
+#define AMD64_GARTAPERTUREBASE 0x94
+#define AMD64_GARTTABLEBASE    0x98
+#define AMD64_GARTCACHECTL     0x9c
+#define AMD64_GARTEN           (1<<0)
+
+static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
 {
+       u32 tmp, ctl;
+
+        /* address of the mappings table */
+        addr >>= 12;
+        tmp = (u32) addr<<4;
+        tmp &= ~0xf;
+        pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp);
+
+        /* Enable GART translation for this hammer. */
+        pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
+        ctl |= GARTEN;
+        ctl &= ~(DISGARTCPU | DISGARTIO);
+        pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
 }
 
-static inline void gart_iommu_shutdown(void)
+static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size)
 {
-}
+       if (!aper_base)
+               return 0;
 
-#endif
+       if (aper_base + aper_size > 0x100000000ULL) {
+               printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n");
+               return 0;
+       }
+       if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
+               printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n");
+               return 0;
+       }
+       if (aper_size < min_size) {
+               printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n",
+                                aper_size>>20, min_size>>20);
+               return 0;
+       }
+
+       return 1;
+}
 
 #endif
index 1de931b263ce142f7b30ae70af6c033cbd3f25d5..0f8504627c41ce8c6d9f168e8ff038a8d15c3d12 100644 (file)
@@ -44,4 +44,6 @@ DECLARE_PER_CPU(int, x2apic_extra_bits);
 extern void uv_cpu_init(void);
 extern int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip);
 
+extern void setup_apic_routing(void);
+
 #endif
index 314434d664e783296a7b120c1cdc9f1844888859..000787df66e6340a0e81b4a705e511692137a53f 100644 (file)
@@ -3,3 +3,9 @@
 #else
 # include "hardirq_64.h"
 #endif
+
+extern u64 arch_irq_stat_cpu(unsigned int cpu);
+#define arch_irq_stat_cpu      arch_irq_stat_cpu
+
+extern u64 arch_irq_stat(void);
+#define arch_irq_stat          arch_irq_stat
index e153f3b447747d83db0bc54c4f0830266686b85d..4514b16cc7236b447444b30caf26c1a75196f498 100644 (file)
@@ -74,6 +74,9 @@ struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()    do { } while (0)
 
+extern void add_highpages_with_active_regions(int nid, unsigned long start_pfn,
+                                       unsigned long end_pfn);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
index 6a9b4ac59bf717c321f6e10d8c74a9e2796e0c31..82f1ac641bd73214115fe7baff23e35153cfd5f0 100644 (file)
@@ -86,8 +86,8 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler);
 #else /* CONFIG_HPET_TIMER */
 
 static inline int hpet_enable(void) { return 0; }
-static inline unsigned long hpet_readl(unsigned long a) { return 0; }
 static inline int is_hpet_enabled(void) { return 0; }
+#define hpet_readl(a) 0
 
 #endif
 #endif /* ASM_X86_HPET_H */
index bf025399d9392ed7910d34c8c0b7309c125f92e9..18f067c310f7880be0f8629e45a91add4b380abb 100644 (file)
@@ -1,5 +1,106 @@
+#ifndef _ASM_HW_IRQ_H
+#define _ASM_HW_IRQ_H
+
+/*
+ * (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *
+ * moved some of the old arch/i386/kernel/irq.h to here. VY
+ *
+ * IRQ/IPI changes taken from work by Thomas Radke
+ * <tomsoft@informatik.tu-chemnitz.de>
+ *
+ * hacked by Andi Kleen for x86-64.
+ * unified by tglx
+ */
+
+#include <asm/irq_vectors.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/percpu.h>
+#include <linux/profile.h>
+#include <linux/smp.h>
+
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/sections.h>
+
+#define platform_legacy_irq(irq)       ((irq) < 16)
+
+/* Interrupt handlers registered during init_IRQ */
+extern void apic_timer_interrupt(void);
+extern void error_interrupt(void);
+extern void spurious_interrupt(void);
+extern void thermal_interrupt(void);
+extern void reschedule_interrupt(void);
+
+extern void invalidate_interrupt(void);
+extern void invalidate_interrupt0(void);
+extern void invalidate_interrupt1(void);
+extern void invalidate_interrupt2(void);
+extern void invalidate_interrupt3(void);
+extern void invalidate_interrupt4(void);
+extern void invalidate_interrupt5(void);
+extern void invalidate_interrupt6(void);
+extern void invalidate_interrupt7(void);
+
+extern void irq_move_cleanup_interrupt(void);
+extern void threshold_interrupt(void);
+
+extern void call_function_interrupt(void);
+
+/* PIC specific functions */
+extern void disable_8259A_irq(unsigned int irq);
+extern void enable_8259A_irq(unsigned int irq);
+extern int i8259A_irq_pending(unsigned int irq);
+extern void make_8259A_irq(unsigned int irq);
+extern void init_8259A(int aeoi);
+
+/* IOAPIC */
+#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
+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 void print_IO_APIC(void);
+extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
+extern void setup_ioapic_dest(void);
+
+#ifdef CONFIG_X86_64
+extern void enable_IO_APIC(void);
+#endif
+
+/* IPI functions */
+extern void send_IPI_self(int vector);
+extern void send_IPI(int dest, int vector);
+
+/* Statistics */
+extern atomic_t irq_err_count;
+extern atomic_t irq_mis_count;
+
+/* EISA */
+extern void eisa_set_level_irq(unsigned int irq);
+
+/* Voyager functions */
+extern asmlinkage void vic_cpi_interrupt(void);
+extern asmlinkage void vic_sys_interrupt(void);
+extern asmlinkage void vic_cmn_interrupt(void);
+extern asmlinkage void qic_timer_interrupt(void);
+extern asmlinkage void qic_invalidate_interrupt(void);
+extern asmlinkage void qic_reschedule_interrupt(void);
+extern asmlinkage void qic_enable_irq_interrupt(void);
+extern asmlinkage void qic_call_function_interrupt(void);
+
 #ifdef CONFIG_X86_32
-# include "hw_irq_32.h"
+extern void (*const interrupt[NR_IRQS])(void);
 #else
-# include "hw_irq_64.h"
+typedef int vector_irq_t[NR_VECTORS];
+DECLARE_PER_CPU(vector_irq_t, vector_irq);
+extern spinlock_t vector_lock;
+#endif
+extern void setup_vector_irq(int cpu);
+
+#endif /* !ASSEMBLY_ */
+
 #endif
diff --git a/include/asm-x86/hw_irq_32.h b/include/asm-x86/hw_irq_32.h
deleted file mode 100644 (file)
index ea88054..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef _ASM_HW_IRQ_H
-#define _ASM_HW_IRQ_H
-
-/*
- *     linux/include/asm/hw_irq.h
- *
- *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- *     moved some of the old arch/i386/kernel/irq.h to here. VY
- *
- *     IRQ/IPI changes taken from work by Thomas Radke
- *     <tomsoft@informatik.tu-chemnitz.de>
- */
-
-#include <linux/profile.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <asm/sections.h>
-
-#define NMI_VECTOR             0x02
-
-/*
- * Various low-level irq details needed by irq.c, process.c,
- * time.c, io_apic.c and smp.c
- *
- * Interrupt entry/exit code at both C and assembly level
- */
-
-extern void (*const interrupt[NR_IRQS])(void);
-
-#ifdef CONFIG_SMP
-void reschedule_interrupt(void);
-void invalidate_interrupt(void);
-void call_function_interrupt(void);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-void apic_timer_interrupt(void);
-void error_interrupt(void);
-void spurious_interrupt(void);
-void thermal_interrupt(void);
-#define platform_legacy_irq(irq)       ((irq) < 16)
-#endif
-
-void disable_8259A_irq(unsigned int irq);
-void enable_8259A_irq(unsigned int irq);
-int i8259A_irq_pending(unsigned int irq);
-void make_8259A_irq(unsigned int irq);
-void init_8259A(int aeoi);
-void send_IPI_self(int vector);
-void init_VISWS_APIC_irqs(void);
-void setup_IO_APIC(void);
-void disable_IO_APIC(void);
-void print_IO_APIC(void);
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
-void send_IPI(int dest, int vector);
-void setup_ioapic_dest(void);
-
-extern unsigned long io_apic_irqs;
-
-extern atomic_t irq_err_count;
-extern atomic_t irq_mis_count;
-
-#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
-
-#endif /* _ASM_HW_IRQ_H */
diff --git a/include/asm-x86/hw_irq_64.h b/include/asm-x86/hw_irq_64.h
deleted file mode 100644 (file)
index 0062ef3..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#ifndef _ASM_HW_IRQ_H
-#define _ASM_HW_IRQ_H
-
-/*
- *     linux/include/asm/hw_irq.h
- *
- *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- *     moved some of the old arch/i386/kernel/irq.h to here. VY
- *
- *     IRQ/IPI changes taken from work by Thomas Radke
- *     <tomsoft@informatik.tu-chemnitz.de>
- *
- *     hacked by Andi Kleen for x86-64.
- */
-
-#ifndef __ASSEMBLY__
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <linux/profile.h>
-#include <linux/smp.h>
-#include <linux/percpu.h>
-#endif
-
-#define NMI_VECTOR             0x02
-/*
- * IDT vectors usable for external interrupt sources start
- * at 0x20:
- */
-#define FIRST_EXTERNAL_VECTOR  0x20
-
-#define IA32_SYSCALL_VECTOR    0x80
-
-
-/* Reserve the lowest usable priority level 0x20 - 0x2f for triggering
- * cleanup after irq migration.
- */
-#define IRQ_MOVE_CLEANUP_VECTOR        FIRST_EXTERNAL_VECTOR
-
-/*
- * Vectors 0x30-0x3f are used for ISA interrupts.
- */
-#define IRQ0_VECTOR            (FIRST_EXTERNAL_VECTOR + 0x10)
-#define IRQ1_VECTOR            (IRQ0_VECTOR + 1)
-#define IRQ2_VECTOR            (IRQ0_VECTOR + 2)
-#define IRQ3_VECTOR            (IRQ0_VECTOR + 3)
-#define IRQ4_VECTOR            (IRQ0_VECTOR + 4)
-#define IRQ5_VECTOR            (IRQ0_VECTOR + 5)
-#define IRQ6_VECTOR            (IRQ0_VECTOR + 6)
-#define IRQ7_VECTOR            (IRQ0_VECTOR + 7)
-#define IRQ8_VECTOR            (IRQ0_VECTOR + 8)
-#define IRQ9_VECTOR            (IRQ0_VECTOR + 9)
-#define IRQ10_VECTOR           (IRQ0_VECTOR + 10)
-#define IRQ11_VECTOR           (IRQ0_VECTOR + 11)
-#define IRQ12_VECTOR           (IRQ0_VECTOR + 12)
-#define IRQ13_VECTOR           (IRQ0_VECTOR + 13)
-#define IRQ14_VECTOR           (IRQ0_VECTOR + 14)
-#define IRQ15_VECTOR           (IRQ0_VECTOR + 15)
-
-/*
- * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
- *
- *  some of the following vectors are 'rare', they are merged
- *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
- *  TLB, reschedule and local APIC vectors are performance-critical.
- */
-#define SPURIOUS_APIC_VECTOR   0xff
-#define ERROR_APIC_VECTOR      0xfe
-#define RESCHEDULE_VECTOR      0xfd
-#define CALL_FUNCTION_VECTOR   0xfc
-/* fb free - please don't readd KDB here because it's useless
-   (hint - think what a NMI bit does to a vector) */
-#define THERMAL_APIC_VECTOR    0xfa
-#define THRESHOLD_APIC_VECTOR   0xf9
-/* f8 free */
-#define INVALIDATE_TLB_VECTOR_END      0xf7
-#define INVALIDATE_TLB_VECTOR_START    0xf0    /* f0-f7 used for TLB flush */
-
-#define NUM_INVALIDATE_TLB_VECTORS     8
-
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR     0xef
-
-/*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
- * we start at 0x41 to spread out vectors evenly between priority
- * levels. (0x80 is the syscall vector)
- */
-#define FIRST_DEVICE_VECTOR    (IRQ15_VECTOR + 2)
-#define FIRST_SYSTEM_VECTOR    0xef   /* duplicated in irq.h */
-
-
-#ifndef __ASSEMBLY__
-
-/* Interrupt handlers registered during init_IRQ */
-void apic_timer_interrupt(void);
-void spurious_interrupt(void);
-void error_interrupt(void);
-void reschedule_interrupt(void);
-void call_function_interrupt(void);
-void irq_move_cleanup_interrupt(void);
-void invalidate_interrupt0(void);
-void invalidate_interrupt1(void);
-void invalidate_interrupt2(void);
-void invalidate_interrupt3(void);
-void invalidate_interrupt4(void);
-void invalidate_interrupt5(void);
-void invalidate_interrupt6(void);
-void invalidate_interrupt7(void);
-void thermal_interrupt(void);
-void threshold_interrupt(void);
-void i8254_timer_resume(void);
-
-typedef int vector_irq_t[NR_VECTORS];
-DECLARE_PER_CPU(vector_irq_t, vector_irq);
-extern void __setup_vector_irq(int cpu);
-extern spinlock_t vector_lock;
-
-/*
- * Various low-level irq details needed by irq.c, process.c,
- * time.c, io_apic.c and smp.c
- *
- * Interrupt entry/exit code at both C and assembly level
- */
-
-extern void disable_8259A_irq(unsigned int irq);
-extern void enable_8259A_irq(unsigned int irq);
-extern int i8259A_irq_pending(unsigned int irq);
-extern void make_8259A_irq(unsigned int irq);
-extern void init_8259A(int aeoi);
-extern void send_IPI_self(int vector);
-extern void init_VISWS_APIC_irqs(void);
-extern void setup_IO_APIC(void);
-extern void enable_IO_APIC(void);
-extern void disable_IO_APIC(void);
-extern void print_IO_APIC(void);
-extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
-extern void send_IPI(int dest, int vector);
-extern void setup_ioapic_dest(void);
-extern void native_init_IRQ(void);
-
-extern unsigned long io_apic_irqs;
-
-extern atomic_t irq_err_count;
-extern atomic_t irq_mis_count;
-
-#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
-
-#include <asm/ptrace.h>
-
-#define IRQ_NAME2(nr) nr##_interrupt(void)
-#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-
-/*
- *     SMP has a few special interrupts for IPI messages
- */
-
-#define BUILD_IRQ(nr)                          \
-       asmlinkage void IRQ_NAME(nr);           \
-       asm("\n.p2align\n"                      \
-           "IRQ" #nr "_interrupt:\n\t"         \
-           "push $~(" #nr ") ; "               \
-           "jmp common_interrupt");
-
-#define platform_legacy_irq(irq)       ((irq) < 16)
-
-#endif
-
-#endif /* _ASM_HW_IRQ_H */
index 45d4df3e51e6919a7632dd1e06eda5728378143c..2f98df91f1f2bef9e7fc7bc47b3a42bbe14403d3 100644 (file)
@@ -55,4 +55,6 @@ static inline void outb_pic(unsigned char value, unsigned int port)
        udelay(2);
 }
 
+extern struct irq_chip i8259A_chip;
+
 #endif /* __ASM_I8259_H__ */
index d5b11f60dbd073d9ae56efe67f38b3d03ba9ba5b..bf5d629b3a39a369256564db15ba2d66eb4a014a 100644 (file)
@@ -3,6 +3,76 @@
 
 #define ARCH_HAS_IOREMAP_WC
 
+#include <linux/compiler.h>
+
+/*
+ * early_ioremap() and early_iounmap() are for temporary early boot-time
+ * mappings, before the real ioremap() is functional.
+ * A boot-time mapping is currently limited to at most 16 pages.
+ */
+#ifndef __ASSEMBLY__
+extern void early_ioremap_init(void);
+extern void early_ioremap_clear(void);
+extern void early_ioremap_reset(void);
+extern void *early_ioremap(unsigned long offset, unsigned long size);
+extern void early_iounmap(void *addr, unsigned long size);
+extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
+#endif
+
+#define build_mmio_read(name, size, type, reg, barrier) \
+static inline type name(const volatile void __iomem *addr) \
+{ type ret; asm volatile("mov" size " %1,%0":"=" reg (ret) \
+:"m" (*(volatile type __force *)addr) barrier); return ret; }
+
+#define build_mmio_write(name, size, type, reg, barrier) \
+static inline void name(type val, volatile void __iomem *addr) \
+{ asm volatile("mov" size " %0,%1": :reg (val), \
+"m" (*(volatile type __force *)addr) barrier); }
+
+build_mmio_read(readb, "b", unsigned char, "q", :"memory")
+build_mmio_read(readw, "w", unsigned short, "r", :"memory")
+build_mmio_read(readl, "l", unsigned int, "r", :"memory")
+
+build_mmio_read(__readb, "b", unsigned char, "q", )
+build_mmio_read(__readw, "w", unsigned short, "r", )
+build_mmio_read(__readl, "l", unsigned int, "r", )
+
+build_mmio_write(writeb, "b", unsigned char, "q", :"memory")
+build_mmio_write(writew, "w", unsigned short, "r", :"memory")
+build_mmio_write(writel, "l", unsigned int, "r", :"memory")
+
+build_mmio_write(__writeb, "b", unsigned char, "q", )
+build_mmio_write(__writew, "w", unsigned short, "r", )
+build_mmio_write(__writel, "l", unsigned int, "r", )
+
+#define readb_relaxed(a) __readb(a)
+#define readw_relaxed(a) __readw(a)
+#define readl_relaxed(a) __readl(a)
+#define __raw_readb __readb
+#define __raw_readw __readw
+#define __raw_readl __readl
+
+#define __raw_writeb __writeb
+#define __raw_writew __writew
+#define __raw_writel __writel
+
+#define mmiowb() barrier()
+
+#ifdef CONFIG_X86_64
+build_mmio_read(readq, "q", unsigned long, "r", :"memory")
+build_mmio_read(__readq, "q", unsigned long, "r", )
+build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
+build_mmio_write(__writeq, "q", unsigned long, "r", )
+
+#define readq_relaxed(a) __readq(a)
+#define __raw_readq __readq
+#define __raw_writeq writeq
+
+/* Let people know we have them */
+#define readq readq
+#define writeq writeq
+#endif
+
 #ifdef CONFIG_X86_32
 # include "io_32.h"
 #else
@@ -16,4 +86,17 @@ extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
                                unsigned long prot_val);
 extern void __iomem *ioremap_wc(unsigned long offset, unsigned long size);
 
+/*
+ * early_ioremap() and early_iounmap() are for temporary early boot-time
+ * mappings, before the real ioremap() is functional.
+ * A boot-time mapping is currently limited to at most 16 pages.
+ */
+extern void early_ioremap_init(void);
+extern void early_ioremap_clear(void);
+extern void early_ioremap_reset(void);
+extern void *early_ioremap(unsigned long offset, unsigned long size);
+extern void early_iounmap(void *addr, unsigned long size);
+extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
+
+
 #endif /* _ASM_X86_IO_H */
index 049e81e797a0919e8090135c5b16fe5b99a32c5e..4df44ed54077453db66bcd1f2a31f10d3519e97c 100644 (file)
@@ -121,18 +121,6 @@ static inline void __iomem *ioremap(resource_size_t offset, unsigned long size)
 
 extern void iounmap(volatile void __iomem *addr);
 
-/*
- * early_ioremap() and early_iounmap() are for temporary early boot-time
- * mappings, before the real ioremap() is functional.
- * A boot-time mapping is currently limited to at most 16 pages.
- */
-extern void early_ioremap_init(void);
-extern void early_ioremap_clear(void);
-extern void early_ioremap_reset(void);
-extern void *early_ioremap(unsigned long offset, unsigned long size);
-extern void early_iounmap(void *addr, unsigned long size);
-extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-
 /*
  * ISA I/O bus memory addresses are 1:1 with the physical address.
  */
@@ -149,55 +137,6 @@ extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-
-static inline unsigned char readb(const volatile void __iomem *addr)
-{
-       return *(volatile unsigned char __force *)addr;
-}
-
-static inline unsigned short readw(const volatile void __iomem *addr)
-{
-       return *(volatile unsigned short __force *)addr;
-}
-
-static inline unsigned int readl(const volatile void __iomem *addr)
-{
-       return *(volatile unsigned int __force *) addr;
-}
-
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-#define __raw_readb readb
-#define __raw_readw readw
-#define __raw_readl readl
-
-static inline void writeb(unsigned char b, volatile void __iomem *addr)
-{
-       *(volatile unsigned char __force *)addr = b;
-}
-
-static inline void writew(unsigned short b, volatile void __iomem *addr)
-{
-       *(volatile unsigned short __force *)addr = b;
-}
-
-static inline void writel(unsigned int b, volatile void __iomem *addr)
-{
-       *(volatile unsigned int __force *)addr = b;
-}
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-
-#define mmiowb()
-
 static inline void
 memset_io(volatile void __iomem *addr, unsigned char val, int count)
 {
index 0930bedf9e4d0ca4636a50d766368106ddf4d3ab..ddd8058a50267766cb398984220462589ee6d362 100644 (file)
@@ -204,77 +204,6 @@ extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-
-static inline __u8 __readb(const volatile void __iomem *addr)
-{
-       return *(__force volatile __u8 *)addr;
-}
-
-static inline __u16 __readw(const volatile void __iomem *addr)
-{
-       return *(__force volatile __u16 *)addr;
-}
-
-static __always_inline __u32 __readl(const volatile void __iomem *addr)
-{
-       return *(__force volatile __u32 *)addr;
-}
-
-static inline __u64 __readq(const volatile void __iomem *addr)
-{
-       return *(__force volatile __u64 *)addr;
-}
-
-#define readb(x) __readb(x)
-#define readw(x) __readw(x)
-#define readl(x) __readl(x)
-#define readq(x) __readq(x)
-#define readb_relaxed(a) readb(a)
-#define readw_relaxed(a) readw(a)
-#define readl_relaxed(a) readl(a)
-#define readq_relaxed(a) readq(a)
-#define __raw_readb readb
-#define __raw_readw readw
-#define __raw_readl readl
-#define __raw_readq readq
-
-#define mmiowb()
-
-static inline void __writel(__u32 b, volatile void __iomem *addr)
-{
-       *(__force volatile __u32 *)addr = b;
-}
-
-static inline void __writeq(__u64 b, volatile void __iomem *addr)
-{
-       *(__force volatile __u64 *)addr = b;
-}
-
-static inline void __writeb(__u8 b, volatile void __iomem *addr)
-{
-       *(__force volatile __u8 *)addr = b;
-}
-
-static inline void __writew(__u16 b, volatile void __iomem *addr)
-{
-       *(__force volatile __u16 *)addr = b;
-}
-
-#define writeq(val, addr) __writeq((val), (addr))
-#define writel(val, addr) __writel((val), (addr))
-#define writew(val, addr) __writew((val), (addr))
-#define writeb(val, addr) __writeb((val), (addr))
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-#define __raw_writeq writeq
-
 void __memcpy_fromio(void *, unsigned long, unsigned);
 void __memcpy_toio(unsigned long, const void *, unsigned);
 
index d593e14f03411df3797562d4e01ed318b00efdc2..14f82bbcb5fd6ee5d09f05be363651258ff4e9bb 100644 (file)
  * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
  */
 
+/* I/O Unit Redirection Table */
+#define IO_APIC_REDIR_VECTOR_MASK      0x000FF
+#define IO_APIC_REDIR_DEST_LOGICAL     0x00800
+#define IO_APIC_REDIR_DEST_PHYSICAL    0x00000
+#define IO_APIC_REDIR_SEND_PENDING     (1 << 12)
+#define IO_APIC_REDIR_REMOTE_IRR       (1 << 14)
+#define IO_APIC_REDIR_LEVEL_TRIGGER    (1 << 15)
+#define IO_APIC_REDIR_MASKED           (1 << 16)
+
 /*
  * The structure of the IO-APIC:
  */
@@ -112,21 +121,32 @@ extern int nr_ioapic_registers[MAX_IO_APICS];
 
 #define MP_MAX_IOAPIC_PIN 127
 
-struct mp_ioapic_routing {
-       int apic_id;
-       int gsi_base;
-       int gsi_end;
-       DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
+struct mp_config_ioapic {
+       unsigned long mp_apicaddr;
+       unsigned int mp_apicid;
+       unsigned char mp_type;
+       unsigned char mp_apicver;
+       unsigned char mp_flags;
+};
+
+struct mp_config_intsrc {
+       unsigned int mp_dstapic;
+       unsigned char mp_type;
+       unsigned char mp_irqtype;
+       unsigned short mp_irqflag;
+       unsigned char mp_srcbus;
+       unsigned char mp_srcbusirq;
+       unsigned char mp_dstirq;
 };
 
 /* I/O APIC entries */
-extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+extern struct mp_config_ioapic mp_ioapics[MAX_IO_APICS];
 
 /* # of MP IRQ source entries */
 extern int mp_irq_entries;
 
 /* MP IRQ source entries */
-extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+extern struct mp_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
 
 /* non-0 if default (table-less) MP configuration */
 extern int mpc_default_type;
@@ -137,6 +157,9 @@ extern int sis_apic_bug;
 /* 1 if "noapic" boot option passed */
 extern int skip_ioapic_setup;
 
+/* 1 if the timer IRQ uses the '8259A Virtual Wire' mode */
+extern int timer_through_8259;
+
 static inline void disable_ioapic_setup(void)
 {
        skip_ioapic_setup = 1;
@@ -162,6 +185,8 @@ extern void ioapic_init_mappings(void);
 
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
+static const int timer_through_8259 = 0;
+static inline void ioapic_init_mappings(void) { }
 #endif
 
 #endif
index 07862fdd23c0e195f76cfb3753d136296c2371cd..068c9a40aa5b10c81f5123bf80c3b212cda32840 100644 (file)
@@ -1,29 +1,34 @@
-#ifndef _ASM_X8664_GART_H
-#define _ASM_X8664_GART_H 1
+#ifndef _ASM_X8664_IOMMU_H
+#define _ASM_X8664_IOMMU_H 1
 
 extern void pci_iommu_shutdown(void);
 extern void no_iommu_init(void);
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
-#ifdef CONFIG_IOMMU
+
+#ifdef CONFIG_GART_IOMMU
+extern int gart_iommu_aperture;
+extern int gart_iommu_aperture_allowed;
+extern int gart_iommu_aperture_disabled;
+
+extern void early_gart_iommu_check(void);
 extern void gart_iommu_init(void);
 extern void gart_iommu_shutdown(void);
 extern void __init gart_parse_options(char *);
-extern void iommu_hole_init(void);
-extern int fallback_aper_order;
-extern int fallback_aper_force;
-extern int iommu_aperture;
-extern int iommu_aperture_allowed;
-extern int iommu_aperture_disabled;
-extern int fix_aperture;
+extern void gart_iommu_hole_init(void);
+
 #else
-#define iommu_aperture 0
-#define iommu_aperture_allowed 0
+#define gart_iommu_aperture            0
+#define gart_iommu_aperture_allowed    0
+#define gart_iommu_aperture_disabled   1
 
-static inline void gart_iommu_shutdown(void)
+static inline void early_gart_iommu_check(void)
 {
 }
 
+static inline void gart_iommu_shutdown(void)
+{
+}
 #endif
 
 #endif
index ecc80f341f37723bd689c26da6efb86241c704f5..196d63c28aa44aa3365977da4b729d59444fcb69 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/hw_irq.h>
 #include <asm/apic.h>
+#include <asm/smp.h>
 
 /*
  * the following functions deal with sending IPIs between CPUs.
index 7ba905465a53e26cacc5ada646eae5abadd5a8c9..1a292575731745bdc9c5734adb426220eac6649c 100644 (file)
@@ -1,5 +1,50 @@
-#ifdef CONFIG_X86_32
-# include "irq_32.h"
+#ifndef _ASM_IRQ_H
+#define _ASM_IRQ_H
+/*
+ *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
+ *
+ *     IRQ/IPI changes taken from work by Thomas Radke
+ *     <tomsoft@informatik.tu-chemnitz.de>
+ */
+
+#include <asm/apicdef.h>
+#include <asm/irq_vectors.h>
+
+static inline int irq_canonicalize(int irq)
+{
+       return ((irq == 2) ? 9 : irq);
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+# define ARCH_HAS_NMI_WATCHDOG
+#endif
+
+#ifdef CONFIG_4KSTACKS
+  extern void irq_ctx_init(int cpu);
+  extern void irq_ctx_exit(int cpu);
+# define __ARCH_HAS_DO_SOFTIRQ
 #else
-# include "irq_64.h"
+# define irq_ctx_init(cpu) do { } while (0)
+# define irq_ctx_exit(cpu) do { } while (0)
+# ifdef CONFIG_X86_64
+#  define __ARCH_HAS_DO_SOFTIRQ
+# endif
+#endif
+
+#ifdef CONFIG_IRQBALANCE
+extern int irqbalance_disable(char *str);
+#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+#include <linux/cpumask.h>
+extern void fixup_irqs(cpumask_t map);
 #endif
+
+extern unsigned int do_IRQ(struct pt_regs *regs);
+extern void init_IRQ(void);
+extern void native_init_IRQ(void);
+
+/* Interrupt vector management */
+extern DECLARE_BITMAP(used_vectors, NR_VECTORS);
+
+#endif /* _ASM_IRQ_H */
diff --git a/include/asm-x86/irq_32.h b/include/asm-x86/irq_32.h
deleted file mode 100644 (file)
index 0b79f31..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _ASM_IRQ_H
-#define _ASM_IRQ_H
-
-/*
- *     linux/include/asm/irq.h
- *
- *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- *     IRQ/IPI changes taken from work by Thomas Radke
- *     <tomsoft@informatik.tu-chemnitz.de>
- */
-
-#include <linux/sched.h>
-/* include comes from machine specific directory */
-#include "irq_vectors.h"
-#include <asm/thread_info.h>
-
-static inline int irq_canonicalize(int irq)
-{
-       return ((irq == 2) ? 9 : irq);
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-# define ARCH_HAS_NMI_WATCHDOG         /* See include/linux/nmi.h */
-#endif
-
-#ifdef CONFIG_4KSTACKS
-  extern void irq_ctx_init(int cpu);
-  extern void irq_ctx_exit(int cpu);
-# define __ARCH_HAS_DO_SOFTIRQ
-#else
-# define irq_ctx_init(cpu) do { } while (0)
-# define irq_ctx_exit(cpu) do { } while (0)
-#endif
-
-#ifdef CONFIG_IRQBALANCE
-extern int irqbalance_disable(char *str);
-#endif
-
-#ifdef CONFIG_HOTPLUG_CPU
-extern void fixup_irqs(cpumask_t map);
-#endif
-
-unsigned int do_IRQ(struct pt_regs *regs);
-void init_IRQ(void);
-void __init native_init_IRQ(void);
-
-/* Interrupt vector management */
-extern DECLARE_BITMAP(used_vectors, NR_VECTORS);
-
-#endif /* _ASM_IRQ_H */
diff --git a/include/asm-x86/irq_64.h b/include/asm-x86/irq_64.h
deleted file mode 100644 (file)
index 083d35a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _ASM_IRQ_H
-#define _ASM_IRQ_H
-
-/*
- *     linux/include/asm/irq.h
- *
- *     (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
- *
- *     IRQ/IPI changes taken from work by Thomas Radke
- *     <tomsoft@informatik.tu-chemnitz.de>
- */
-
-#define TIMER_IRQ 0
-
-/*
- * 16 8259A IRQ's, 208 potential APIC interrupt sources.
- * Right now the APIC is mostly only used for SMP.
- * 256 vectors is an architectural limit. (we can have
- * more than 256 devices theoretically, but they will
- * have to use shared interrupts)
- * Since vectors 0x00-0x1f are used/reserved for the CPU,
- * the usable vector space is 0x20-0xff (224 vectors)
- */
-
-/*
- * The maximum number of vectors supported by x86_64 processors
- * is limited to 256. For processors other than x86_64, NR_VECTORS
- * should be changed accordingly.
- */
-#define NR_VECTORS 256
-
-#define FIRST_SYSTEM_VECTOR    0xef   /* duplicated in hw_irq.h */
-
-#define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
-#define NR_IRQ_VECTORS NR_IRQS
-
-static inline int irq_canonicalize(int irq)
-{
-       return ((irq == 2) ? 9 : irq);
-}
-
-#define ARCH_HAS_NMI_WATCHDOG          /* See include/linux/nmi.h */
-
-#ifdef CONFIG_HOTPLUG_CPU
-#include <linux/cpumask.h>
-extern void fixup_irqs(cpumask_t map);
-#endif
-
-#define __ARCH_HAS_DO_SOFTIRQ 1
-
-#endif /* _ASM_IRQ_H */
diff --git a/include/asm-x86/irq_vectors.h b/include/asm-x86/irq_vectors.h
new file mode 100644 (file)
index 0000000..0ac864e
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef _ASM_IRQ_VECTORS_H
+#define _ASM_IRQ_VECTORS_H
+
+#include <linux/threads.h>
+
+#define NMI_VECTOR             0x02
+
+/*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR  0x20
+
+#ifdef CONFIG_X86_32
+# define SYSCALL_VECTOR                0x80
+#else
+# define IA32_SYSCALL_VECTOR   0x80
+#endif
+
+/*
+ * Reserve the lowest usable priority level 0x20 - 0x2f for triggering
+ * cleanup after irq migration on 64 bit.
+ */
+#define IRQ_MOVE_CLEANUP_VECTOR        FIRST_EXTERNAL_VECTOR
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts on 32 bit.
+ * Vectors 0x30-0x3f are used for ISA interrupts on 64 bit.
+ */
+#ifdef CONFIG_X86_32
+#define IRQ0_VECTOR            (FIRST_EXTERNAL_VECTOR)
+#else
+#define IRQ0_VECTOR            (FIRST_EXTERNAL_VECTOR + 0x10)
+#endif
+#define IRQ1_VECTOR            (IRQ0_VECTOR + 1)
+#define IRQ2_VECTOR            (IRQ0_VECTOR + 2)
+#define IRQ3_VECTOR            (IRQ0_VECTOR + 3)
+#define IRQ4_VECTOR            (IRQ0_VECTOR + 4)
+#define IRQ5_VECTOR            (IRQ0_VECTOR + 5)
+#define IRQ6_VECTOR            (IRQ0_VECTOR + 6)
+#define IRQ7_VECTOR            (IRQ0_VECTOR + 7)
+#define IRQ8_VECTOR            (IRQ0_VECTOR + 8)
+#define IRQ9_VECTOR            (IRQ0_VECTOR + 9)
+#define IRQ10_VECTOR           (IRQ0_VECTOR + 10)
+#define IRQ11_VECTOR           (IRQ0_VECTOR + 11)
+#define IRQ12_VECTOR           (IRQ0_VECTOR + 12)
+#define IRQ13_VECTOR           (IRQ0_VECTOR + 13)
+#define IRQ14_VECTOR           (IRQ0_VECTOR + 14)
+#define IRQ15_VECTOR           (IRQ0_VECTOR + 15)
+
+/*
+ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
+ *
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ *
+ *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
+ */
+#ifdef CONFIG_X86_32
+
+# define SPURIOUS_APIC_VECTOR          0xff
+# define ERROR_APIC_VECTOR             0xfe
+# define INVALIDATE_TLB_VECTOR         0xfd
+# define RESCHEDULE_VECTOR             0xfc
+# define CALL_FUNCTION_VECTOR          0xfb
+# define THERMAL_APIC_VECTOR           0xf0
+
+#else
+
+#define SPURIOUS_APIC_VECTOR           0xff
+#define ERROR_APIC_VECTOR              0xfe
+#define RESCHEDULE_VECTOR              0xfd
+#define CALL_FUNCTION_VECTOR           0xfc
+#define THERMAL_APIC_VECTOR            0xfa
+#define THRESHOLD_APIC_VECTOR          0xf9
+#define INVALIDATE_TLB_VECTOR_END      0xf7
+#define INVALIDATE_TLB_VECTOR_START    0xf0    /* f0-f7 used for TLB flush */
+
+#define NUM_INVALIDATE_TLB_VECTORS     8
+
+#endif
+
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR     0xef
+
+/*
+ * First APIC vector available to drivers: (vectors 0x30-0xee) we
+ * start at 0x31(0x41) to spread out vectors evenly between priority
+ * levels. (0x80 is the syscall vector)
+ */
+#ifdef CONFIG_X86_32
+# define FIRST_DEVICE_VECTOR   0x31
+#else
+# define FIRST_DEVICE_VECTOR   (IRQ15_VECTOR + 2)
+#endif
+
+#define NR_VECTORS             256
+
+#define FPU_IRQ                        13
+
+#define        FIRST_VM86_IRQ          3
+#define LAST_VM86_IRQ          15
+#define invalid_vm86_irq(irq)  ((irq) < 3 || (irq) > 15)
+
+#if !defined(CONFIG_X86_VOYAGER)
+
+# if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT) || defined(CONFIG_X86_VISWS)
+
+#  define NR_IRQS              224
+
+#  if (224 >= 32 * NR_CPUS)
+#   define NR_IRQ_VECTORS      NR_IRQS
+#  else
+#   define NR_IRQ_VECTORS      (32 * NR_CPUS)
+#  endif
+
+# else /* IO_APIC || PARAVIRT */
+
+#  define NR_IRQS              16
+#  define NR_IRQ_VECTORS       NR_IRQS
+
+# endif
+
+#else /* !VISWS && !VOYAGER */
+
+# define NR_IRQS               224
+# define NR_IRQ_VECTORS                NR_IRQS
+
+#endif /* VISWS */
+
+/* Voyager specific defines */
+/* These define the CPIs we use in linux */
+#define VIC_CPI_LEVEL0                 0
+#define VIC_CPI_LEVEL1                 1
+/* now the fake CPIs */
+#define VIC_TIMER_CPI                  2
+#define VIC_INVALIDATE_CPI             3
+#define VIC_RESCHEDULE_CPI             4
+#define VIC_ENABLE_IRQ_CPI             5
+#define VIC_CALL_FUNCTION_CPI          6
+
+/* Now the QIC CPIs:  Since we don't need the two initial levels,
+ * these are 2 less than the VIC CPIs */
+#define QIC_CPI_OFFSET                 1
+#define QIC_TIMER_CPI                  (VIC_TIMER_CPI - QIC_CPI_OFFSET)
+#define QIC_INVALIDATE_CPI             (VIC_INVALIDATE_CPI - QIC_CPI_OFFSET)
+#define QIC_RESCHEDULE_CPI             (VIC_RESCHEDULE_CPI - QIC_CPI_OFFSET)
+#define QIC_ENABLE_IRQ_CPI             (VIC_ENABLE_IRQ_CPI - QIC_CPI_OFFSET)
+#define QIC_CALL_FUNCTION_CPI          (VIC_CALL_FUNCTION_CPI - QIC_CPI_OFFSET)
+
+#define VIC_START_FAKE_CPI             VIC_TIMER_CPI
+#define VIC_END_FAKE_CPI               VIC_CALL_FUNCTION_CPI
+
+/* this is the SYS_INT CPI. */
+#define VIC_SYS_INT                    8
+#define VIC_CMN_INT                    15
+
+/* This is the boot CPI for alternate processors.  It gets overwritten
+ * by the above once the system has activated all available processors */
+#define VIC_CPU_BOOT_CPI               VIC_CPI_LEVEL0
+#define VIC_CPU_BOOT_ERRATA_CPI                (VIC_CPI_LEVEL0 + 8)
+
+
+#endif /* _ASM_IRQ_VECTORS_H */
index c242527f970e8e7f8ae33e6dc080216560fbaa96..17e7a1701c97be5c6a734e25e2add35347bb96b5 100644 (file)
@@ -111,14 +111,35 @@ static inline unsigned long __raw_local_irq_save(void)
 #define DISABLE_INTERRUPTS(x)  cli
 
 #ifdef CONFIG_X86_64
+#define SWAPGS swapgs
+/*
+ * Currently paravirt can't handle swapgs nicely when we
+ * don't have a stack we can rely on (such as a user space
+ * stack).  So we either find a way around these or just fault
+ * and emulate if a guest tries to call swapgs directly.
+ *
+ * Either way, this is a good way to document that we don't
+ * have a reliable stack. x86_64 only.
+ */
+#define SWAPGS_UNSAFE_STACK    swapgs
+
+#define PARAVIRT_ADJUST_EXCEPTION_FRAME        /*  */
+
 #define INTERRUPT_RETURN       iretq
-#define ENABLE_INTERRUPTS_SYSCALL_RET                  \
-                       movq    %gs:pda_oldrsp, %rsp;   \
-                       swapgs;                         \
-                       sysretq;
+#define USERGS_SYSRET64                                \
+       swapgs;                                 \
+       sysretq;
+#define USERGS_SYSRET32                                \
+       swapgs;                                 \
+       sysretl
+#define ENABLE_INTERRUPTS_SYSEXIT32            \
+       swapgs;                                 \
+       sti;                                    \
+       sysexit
+
 #else
 #define INTERRUPT_RETURN               iret
-#define ENABLE_INTERRUPTS_SYSCALL_RET  sti; sysexit
+#define ENABLE_INTERRUPTS_SYSEXIT      sti; sysexit
 #define GET_CR0_INTO_EAX               movl %cr0, %eax
 #endif
 
@@ -169,16 +190,6 @@ static inline void trace_hardirqs_fixup(void)
 #else
 
 #ifdef CONFIG_X86_64
-/*
- * Currently paravirt can't handle swapgs nicely when we
- * don't have a stack we can rely on (such as a user space
- * stack).  So we either find a way around these or just fault
- * and emulate if a guest tries to call swapgs directly.
- *
- * Either way, this is a good way to document that we don't
- * have a reliable stack. x86_64 only.
- */
-#define SWAPGS_UNSAFE_STACK    swapgs
 #define ARCH_TRACE_IRQS_ON             call trace_hardirqs_on_thunk
 #define ARCH_TRACE_IRQS_OFF            call trace_hardirqs_off_thunk
 #define ARCH_LOCKDEP_SYS_EXIT          call lockdep_sys_exit_thunk
index 8327907c79bf0092409f95ed14f6184a73f0434a..017c8c19ad8f874e0cc461c388f58716545eda34 100644 (file)
@@ -81,7 +81,7 @@ static inline int multi_timer_check(int apic, int irq)
 
 static inline int apicid_to_node(int logical_apicid)
 {
-       return (0);
+       return apicid_2_node[hard_smp_processor_id()];
 }
 
 static inline int cpu_present_to_apicid(int mps_cpu)
diff --git a/include/asm-x86/mach-bigsmp/mach_mpspec.h b/include/asm-x86/mach-bigsmp/mach_mpspec.h
deleted file mode 100644 (file)
index 6b5dadc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __ASM_MACH_MPSPEC_H
-#define __ASM_MACH_MPSPEC_H
-
-#define MAX_IRQ_SOURCES 256
-
-#define MAX_MP_BUSSES 32
-
-#endif /* __ASM_MACH_MPSPEC_H */
diff --git a/include/asm-x86/mach-default/irq_vectors.h b/include/asm-x86/mach-default/irq_vectors.h
deleted file mode 100644 (file)
index 881c63c..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * This file should contain #defines for all of the interrupt vector
- * numbers used by this architecture.
- *
- * In addition, there are some standard defines:
- *
- *     FIRST_EXTERNAL_VECTOR:
- *             The first free place for external interrupts
- *
- *     SYSCALL_VECTOR:
- *             The IRQ vector a syscall makes the user to kernel transition
- *             under.
- *
- *     TIMER_IRQ:
- *             The IRQ number the timer interrupt comes in at.
- *
- *     NR_IRQS:
- *             The total number of interrupt vectors (including all the
- *             architecture specific interrupts) needed.
- *
- */                    
-#ifndef _ASM_IRQ_VECTORS_H
-#define _ASM_IRQ_VECTORS_H
-
-/*
- * IDT vectors usable for external interrupt sources start
- * at 0x20:
- */
-#define FIRST_EXTERNAL_VECTOR  0x20
-
-#define SYSCALL_VECTOR         0x80
-
-/*
- * Vectors 0x20-0x2f are used for ISA interrupts.
- */
-
-/*
- * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
- *
- *  some of the following vectors are 'rare', they are merged
- *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
- *  TLB, reschedule and local APIC vectors are performance-critical.
- *
- *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
- */
-#define SPURIOUS_APIC_VECTOR   0xff
-#define ERROR_APIC_VECTOR      0xfe
-#define INVALIDATE_TLB_VECTOR  0xfd
-#define RESCHEDULE_VECTOR      0xfc
-#define CALL_FUNCTION_VECTOR   0xfb
-
-#define THERMAL_APIC_VECTOR    0xf0
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR     0xef
-
-/*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
- * we start at 0x31 to spread out vectors evenly between priority
- * levels. (0x80 is the syscall vector)
- */
-#define FIRST_DEVICE_VECTOR    0x31
-#define FIRST_SYSTEM_VECTOR    0xef
-
-#define TIMER_IRQ 0
-
-/*
- * 16 8259A IRQ's, 208 potential APIC interrupt sources.
- * Right now the APIC is mostly only used for SMP.
- * 256 vectors is an architectural limit. (we can have
- * more than 256 devices theoretically, but they will
- * have to use shared interrupts)
- * Since vectors 0x00-0x1f are used/reserved for the CPU,
- * the usable vector space is 0x20-0xff (224 vectors)
- */
-
-/*
- * The maximum number of vectors supported by i386 processors
- * is limited to 256. For processors other than i386, NR_VECTORS
- * should be changed accordingly.
- */
-#define NR_VECTORS 256
-
-#include "irq_vectors_limits.h"
-
-#define FPU_IRQ                        13
-
-#define        FIRST_VM86_IRQ          3
-#define LAST_VM86_IRQ          15
-#define invalid_vm86_irq(irq)  ((irq) < 3 || (irq) > 15)
-
-
-#endif /* _ASM_IRQ_VECTORS_H */
diff --git a/include/asm-x86/mach-default/irq_vectors_limits.h b/include/asm-x86/mach-default/irq_vectors_limits.h
deleted file mode 100644 (file)
index a90c7a6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _ASM_IRQ_VECTORS_LIMITS_H
-#define _ASM_IRQ_VECTORS_LIMITS_H
-
-#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
-#define NR_IRQS 224
-# if (224 >= 32 * NR_CPUS)
-# define NR_IRQ_VECTORS NR_IRQS
-# else
-# define NR_IRQ_VECTORS (32 * NR_CPUS)
-# endif
-#else
-#define NR_IRQS 16
-#define NR_IRQ_VECTORS NR_IRQS
-#endif
-
-#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
index 21003b56ae959e0db51ebd1ac689ccb83ecbda37..0b2cde5e1b74b38641c4cea560784be0d7716a9b 100644 (file)
@@ -77,7 +77,11 @@ static inline void setup_apic_routing(void)
 
 static inline int apicid_to_node(int logical_apicid)
 {
+#ifdef CONFIG_SMP
+       return apicid_2_node[hard_smp_processor_id()];
+#else
        return 0;
+#endif
 }
 #endif
 
index 605e3ccb991bde9af67cda27af76fe8fc12b4fb9..38846208b548dc0681498484f585c0da99c3a471 100644 (file)
@@ -1,7 +1,3 @@
 /* Hook to call BIOS initialisation function */
 
 /* no action for generic */
-
-#ifndef ARCH_SETUP
-#define ARCH_SETUP
-#endif
index 56d0e1fa025895d1af57588e22a44820ec08a59e..56d001b9dce4f0177b409c72982e902d4d8ef6e9 100644 (file)
@@ -3,7 +3,9 @@
 
 static inline void smpboot_clear_io_apic_irqs(void)
 {
+#ifdef CONFIG_X86_IO_APIC
        io_apic_irqs = 0;
+#endif
 }
 
 static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
@@ -35,17 +37,23 @@ static inline void smpboot_restore_warm_reset_vector(void)
 
 static inline void __init smpboot_setup_io_apic(void)
 {
+#ifdef CONFIG_X86_IO_APIC
        /*
         * Here we can be sure that there is an IO-APIC in the system. Let's
         * go and set it up:
         */
        if (!skip_ioapic_setup && nr_ioapics)
                setup_IO_APIC();
-       else
+       else {
                nr_ioapics = 0;
+               localise_nmi_watchdog();
+       }
+#endif
 }
 
 static inline void smpboot_clear_io_apic(void)
 {
+#ifdef CONFIG_X86_IO_APIC
        nr_ioapics = 0;
+#endif
 }
diff --git a/include/asm-x86/mach-es7000/mach_mpspec.h b/include/asm-x86/mach-es7000/mach_mpspec.h
deleted file mode 100644 (file)
index b1f5039..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __ASM_MACH_MPSPEC_H
-#define __ASM_MACH_MPSPEC_H
-
-#define MAX_IRQ_SOURCES 256
-
-#define MAX_MP_BUSSES 256
-
-#endif /* __ASM_MACH_MPSPEC_H */
index 0d0b5ba2e9d1a87d53022ea1eaf8a462c19654f2..586cadbf3787ce9c98449921db1c14c942d418bc 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef _MACH_MPPARSE_H
 #define _MACH_MPPARSE_H 1
 
-int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid); 
-int acpi_madt_oem_check(char *oem_id, char *oem_table_id); 
+
+extern int mps_oem_check(struct mp_config_table *mpc, char *oem,
+                        char *productid);
+
+extern int acpi_madt_oem_check(char *oem_id, char *oem_table_id);
 
 #endif
index 75a56e5afbe7093db489441b3135c27946ea3234..d802465e026a4a5adb6834f90c0ea74caa672617 100644 (file)
@@ -20,8 +20,14 @@ static inline cpumask_t target_cpus(void)
 #define INT_DELIVERY_MODE dest_LowestPrio
 #define INT_DEST_MODE 0     /* physical delivery on LOCAL quad */
  
-#define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap)
-#define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map)
+static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
+{
+       return physid_isset(apicid, bitmap);
+}
+static inline unsigned long check_apicid_present(int bit)
+{
+       return physid_isset(bit, phys_cpu_present_map);
+}
 #define apicid_cluster(apicid) (apicid & 0xF0)
 
 static inline int apic_id_registered(void)
@@ -77,11 +83,6 @@ static inline int cpu_present_to_apicid(int mps_cpu)
                return BAD_APICID;
 }
 
-static inline int generate_logical_apicid(int quad, int phys_apicid)
-{
-       return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1);
-}
-
 static inline int apicid_to_node(int logical_apicid) 
 {
        return logical_apicid >> 4;
@@ -95,30 +96,6 @@ static inline physid_mask_t apicid_to_cpu_present(int logical_apicid)
        return physid_mask_of_physid(cpu + 4*node);
 }
 
-struct mpc_config_translation {
-       unsigned char mpc_type;
-       unsigned char trans_len;
-       unsigned char trans_type;
-       unsigned char trans_quad;
-       unsigned char trans_global;
-       unsigned char trans_local;
-       unsigned short trans_reserved;
-};
-
-static inline int mpc_apic_id(struct mpc_config_processor *m, 
-                       struct mpc_config_translation *translation_record)
-{
-       int quad = translation_record->trans_quad;
-       int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid);
-
-       printk("Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n",
-              m->mpc_apicid,
-              (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
-              (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
-              m->mpc_apicver, quad, logical_apicid);
-       return logical_apicid;
-}
-
 extern void *xquad_portio;
 
 static inline void setup_portio_remap(void)
index 459b124011872c9337ad0e6bd58b4a509ef3464a..626aef6b155f1498eee4ab3594eab6a4adeee00d 100644 (file)
@@ -1,14 +1,7 @@
 #ifndef __ASM_MACH_MPPARSE_H
 #define __ASM_MACH_MPPARSE_H
 
-extern void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
-                            struct mpc_config_translation *translation);
-extern void mpc_oem_pci_bus(struct mpc_config_bus *m,
-       struct mpc_config_translation *translation);
-
-/* Hook from generic ACPI tables.c */
-static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-}
+extern void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
+                               char *productid);
 
 #endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-x86/mach-numaq/mach_mpspec.h b/include/asm-x86/mach-numaq/mach_mpspec.h
deleted file mode 100644 (file)
index dffb098..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __ASM_MACH_MPSPEC_H
-#define __ASM_MACH_MPSPEC_H
-
-#define MAX_IRQ_SOURCES 512
-
-#define MAX_MP_BUSSES 32
-
-#endif /* __ASM_MACH_MPSPEC_H */
diff --git a/include/asm-x86/mach-summit/mach_mpspec.h b/include/asm-x86/mach-summit/mach_mpspec.h
deleted file mode 100644 (file)
index bd76552..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __ASM_MACH_MPSPEC_H
-#define __ASM_MACH_MPSPEC_H
-
-#define MAX_IRQ_SOURCES 256
-
-/* Maximum 256 PCI busses, plus 1 ISA bus in each of 4 cabinets. */
-#define MAX_MP_BUSSES 260
-
-#endif /* __ASM_MACH_MPSPEC_H */
diff --git a/include/asm-x86/mach-visws/irq_vectors.h b/include/asm-x86/mach-visws/irq_vectors.h
deleted file mode 100644 (file)
index cb572d8..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef _ASM_IRQ_VECTORS_H
-#define _ASM_IRQ_VECTORS_H
-
-/*
- * IDT vectors usable for external interrupt sources start
- * at 0x20:
- */
-#define FIRST_EXTERNAL_VECTOR  0x20
-
-#define SYSCALL_VECTOR         0x80
-
-/*
- * Vectors 0x20-0x2f are used for ISA interrupts.
- */
-
-/*
- * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
- *
- *  some of the following vectors are 'rare', they are merged
- *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
- *  TLB, reschedule and local APIC vectors are performance-critical.
- *
- *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
- */
-#define SPURIOUS_APIC_VECTOR   0xff
-#define ERROR_APIC_VECTOR      0xfe
-#define INVALIDATE_TLB_VECTOR  0xfd
-#define RESCHEDULE_VECTOR      0xfc
-#define CALL_FUNCTION_VECTOR   0xfb
-
-#define THERMAL_APIC_VECTOR    0xf0
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR     0xef
-
-/*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
- * we start at 0x31 to spread out vectors evenly between priority
- * levels. (0x80 is the syscall vector)
- */
-#define FIRST_DEVICE_VECTOR    0x31
-#define FIRST_SYSTEM_VECTOR    0xef
-
-#define TIMER_IRQ 0
-
-/*
- * IRQ definitions
- */
-#define NR_VECTORS 256
-#define NR_IRQS 224
-#define NR_IRQ_VECTORS NR_IRQS
-
-#define FPU_IRQ                        13
-
-#define        FIRST_VM86_IRQ          3
-#define LAST_VM86_IRQ          15
-#define invalid_vm86_irq(irq)  ((irq) < 3 || (irq) > 15)
-
-#endif /* _ASM_IRQ_VECTORS_H */
index a9ef33a8a9950a26d1dcfc533faebab0841cb80b..6943e7a1d0e6c01dac8374b09e1b55eaef31b9b0 100644 (file)
@@ -1,103 +1 @@
-#ifndef __ASM_MACH_APIC_H
-#define __ASM_MACH_APIC_H
-
-#include <mach_apicdef.h>
-#include <asm/smp.h>
-
-#define APIC_DFR_VALUE (APIC_DFR_FLAT)
-
-#define no_balance_irq (0)
-#define esr_disable (0)
-
-#define INT_DELIVERY_MODE dest_LowestPrio
-#define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
-
-#ifdef CONFIG_SMP
- #define TARGET_CPUS cpu_online_map
-#else
- #define TARGET_CPUS cpumask_of_cpu(0)
-#endif
-
-#define check_apicid_used(bitmap, apicid)      physid_isset(apicid, bitmap)
-#define check_apicid_present(bit)              physid_isset(bit, phys_cpu_present_map)
-
-static inline int apic_id_registered(void)
-{
-       return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map);
-}
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
- */
-static inline void init_apic_ldr(void)
-{
-       unsigned long val;
-
-       apic_write_around(APIC_DFR, APIC_DFR_VALUE);
-       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-       val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
-       apic_write_around(APIC_LDR, val);
-}
-
-static inline void summit_check(char *oem, char *productid) 
-{
-}
-
-static inline void setup_apic_routing(void)
-{
-}
-
-static inline int apicid_to_node(int logical_apicid)
-{
-       return 0;
-}
-
-/* Mapping from cpu number to logical apicid */
-static inline int cpu_to_logical_apicid(int cpu)
-{
-       return 1 << cpu;
-}
-
-static inline int cpu_present_to_apicid(int mps_cpu)
-{
-       if (mps_cpu < get_physical_broadcast())
-               return mps_cpu;
-       else
-               return BAD_APICID;
-}
-
-static inline physid_mask_t apicid_to_cpu_present(int apicid)
-{
-       return physid_mask_of_physid(apicid);
-}
-
-#define WAKE_SECONDARY_VIA_INIT
-
-static inline void setup_portio_remap(void)
-{
-}
-
-static inline void enable_apic_mode(void)
-{
-}
-
-static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
-{
-       return physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map);
-}
-
-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
-{
-       return cpus_addr(cpumask)[0];
-}
-
-static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
-{
-       return cpuid_apic >> index_msb;
-}
-
-#endif /* __ASM_MACH_APIC_H */
+#include "../mach-default/mach_apic.h"
index 826cfa97d778f1684b911012f3d5a8d053124901..42711d152a93568a57c71bcdf552ea983c525488 100644 (file)
@@ -1,12 +1 @@
-#ifndef __ASM_MACH_APICDEF_H
-#define __ASM_MACH_APICDEF_H
-
-#define         APIC_ID_MASK            (0xF<<24)
-
-static inline unsigned get_apic_id(unsigned long x)
-{
-               return (((x)>>24)&0xF);
-}
-#define         GET_APIC_ID(x)  get_apic_id(x)
-
-#endif
+#include "../mach-default/mach_apicdef.h"
index 33f700ef68316048cdb049f436d187d57854295a..fa4766ca2d10e91342fafdaf98e6b56191853844 100644 (file)
@@ -1,8 +1 @@
-/* Hook to call BIOS initialisation function */
-
-extern unsigned long sgivwfb_mem_phys;
-extern unsigned long sgivwfb_mem_size;
-
-/* no action for visws */
-
-#define ARCH_SETUP
+#include "../mach-default/setup_arch.h"
index c9b83e395a2ee60327f181b4d3ac87804c4f984c..e4433ca88715fa104dc9a774e629da01b016b78e 100644 (file)
@@ -1,28 +1 @@
-static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
-{
-       CMOS_WRITE(0xa, 0xf);
-       local_flush_tlb();
-       Dprintk("1.\n");
-       *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
-       Dprintk("2.\n");
-       *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
-       Dprintk("3.\n");
-}
-
-/* for visws do nothing for any of these */
-
-static inline void smpboot_clear_io_apic_irqs(void)
-{
-}
-
-static inline void smpboot_restore_warm_reset_vector(void)
-{
-}
-
-static inline void smpboot_setup_io_apic(void)
-{
-}
-
-static inline void smpboot_clear_io_apic(void)
-{
-}
+#include "../mach-default/smpboot_hooks.h"
diff --git a/include/asm-x86/mach-voyager/irq_vectors.h b/include/asm-x86/mach-voyager/irq_vectors.h
deleted file mode 100644 (file)
index 165421f..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/* Copyright (C) 2002
- *
- * Author: James.Bottomley@HansenPartnership.com
- *
- * linux/arch/i386/voyager/irq_vectors.h
- *
- * This file provides definitions for the VIC and QIC CPIs
- */
-
-#ifndef _ASM_IRQ_VECTORS_H
-#define _ASM_IRQ_VECTORS_H
-
-/*
- * IDT vectors usable for external interrupt sources start
- * at 0x20:
- */
-#define FIRST_EXTERNAL_VECTOR  0x20
-
-#define SYSCALL_VECTOR         0x80
-
-/*
- * Vectors 0x20-0x2f are used for ISA interrupts.
- */
-
-/* These define the CPIs we use in linux */
-#define VIC_CPI_LEVEL0                 0
-#define VIC_CPI_LEVEL1                 1
-/* now the fake CPIs */
-#define VIC_TIMER_CPI                  2
-#define VIC_INVALIDATE_CPI             3
-#define VIC_RESCHEDULE_CPI             4
-#define VIC_ENABLE_IRQ_CPI             5
-#define VIC_CALL_FUNCTION_CPI          6
-
-/* Now the QIC CPIs:  Since we don't need the two initial levels,
- * these are 2 less than the VIC CPIs */
-#define QIC_CPI_OFFSET                 1
-#define QIC_TIMER_CPI                  (VIC_TIMER_CPI - QIC_CPI_OFFSET)
-#define QIC_INVALIDATE_CPI             (VIC_INVALIDATE_CPI - QIC_CPI_OFFSET)
-#define QIC_RESCHEDULE_CPI             (VIC_RESCHEDULE_CPI - QIC_CPI_OFFSET)
-#define QIC_ENABLE_IRQ_CPI             (VIC_ENABLE_IRQ_CPI - QIC_CPI_OFFSET)
-#define QIC_CALL_FUNCTION_CPI          (VIC_CALL_FUNCTION_CPI - QIC_CPI_OFFSET)
-
-#define VIC_START_FAKE_CPI             VIC_TIMER_CPI
-#define VIC_END_FAKE_CPI               VIC_CALL_FUNCTION_CPI
-
-/* this is the SYS_INT CPI. */
-#define VIC_SYS_INT                    8
-#define VIC_CMN_INT                    15
-
-/* This is the boot CPI for alternate processors.  It gets overwritten
- * by the above once the system has activated all available processors */
-#define VIC_CPU_BOOT_CPI               VIC_CPI_LEVEL0
-#define VIC_CPU_BOOT_ERRATA_CPI                (VIC_CPI_LEVEL0 + 8)
-
-#define NR_VECTORS 256
-#define NR_IRQS 224
-#define NR_IRQ_VECTORS NR_IRQS
-
-#define FPU_IRQ                                13
-
-#define        FIRST_VM86_IRQ          3
-#define LAST_VM86_IRQ          15
-#define invalid_vm86_irq(irq)  ((irq) < 3 || (irq) > 15)
-
-#ifndef __ASSEMBLY__
-extern asmlinkage void vic_cpi_interrupt(void);
-extern asmlinkage void vic_sys_interrupt(void);
-extern asmlinkage void vic_cmn_interrupt(void);
-extern asmlinkage void qic_timer_interrupt(void);
-extern asmlinkage void qic_invalidate_interrupt(void);
-extern asmlinkage void qic_reschedule_interrupt(void);
-extern asmlinkage void qic_enable_irq_interrupt(void);
-extern asmlinkage void qic_call_function_interrupt(void);
-#endif /* !__ASSEMBLY__ */
-
-#endif /* _ASM_IRQ_VECTORS_H */
diff --git a/include/asm-x86/mmconfig.h b/include/asm-x86/mmconfig.h
new file mode 100644 (file)
index 0000000..95beda0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASM_MMCONFIG_H
+#define _ASM_MMCONFIG_H
+
+#ifdef CONFIG_PCI_MMCONFIG
+extern void __cpuinit fam10h_check_enable_mmcfg(void);
+extern void __init check_enable_amd_mmconf_dmi(void);
+#else
+static inline void fam10h_check_enable_mmcfg(void) { }
+static inline void check_enable_amd_mmconf_dmi(void) { }
+#endif
+
+#endif
index 6598450da6c646db85153ebda68dc544a807d3f6..fac57014e7c6a4a5dbb62a7ac9e884f400c57870 100644 (file)
@@ -1,5 +1,37 @@
+#ifndef __ASM_X86_MMU_CONTEXT_H
+#define __ASM_X86_MMU_CONTEXT_H
+
+#include <asm/desc.h>
+#include <asm/atomic.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/paravirt.h>
+#ifndef CONFIG_PARAVIRT
+#include <asm-generic/mm_hooks.h>
+
+static inline void paravirt_activate_mm(struct mm_struct *prev,
+                                       struct mm_struct *next)
+{
+}
+#endif /* !CONFIG_PARAVIRT */
+
+/*
+ * Used for LDT copy/destruction.
+ */
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+void destroy_context(struct mm_struct *mm);
+
 #ifdef CONFIG_X86_32
 # include "mmu_context_32.h"
 #else
 # include "mmu_context_64.h"
 #endif
+
+#define activate_mm(prev, next)                        \
+do {                                           \
+       paravirt_activate_mm((prev), (next));   \
+       switch_mm((prev), (next), NULL);        \
+} while (0);
+
+
+#endif /* __ASM_X86_MMU_CONTEXT_H */
index 9756ae0f1dd3acd1dca75744946afdaa824077b3..824fc575c6d8370f03d747b6abedaadf21882903 100644 (file)
@@ -1,28 +1,6 @@
 #ifndef __I386_SCHED_H
 #define __I386_SCHED_H
 
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
-#include <asm/paravirt.h>
-#ifndef CONFIG_PARAVIRT
-#include <asm-generic/mm_hooks.h>
-
-static inline void paravirt_activate_mm(struct mm_struct *prev,
-                                       struct mm_struct *next)
-{
-}
-#endif /* !CONFIG_PARAVIRT */
-
-
-/*
- * Used for LDT copy/destruction.
- */
-int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
-void destroy_context(struct mm_struct *mm);
-
-
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 #ifdef CONFIG_SMP
@@ -75,10 +53,4 @@ static inline void switch_mm(struct mm_struct *prev,
 #define deactivate_mm(tsk, mm)                 \
        asm("movl %0,%%gs": :"r" (0));
 
-#define activate_mm(prev, next)                        \
-do {                                           \
-       paravirt_activate_mm((prev), (next));   \
-       switch_mm((prev), (next), NULL);        \
-} while (0);
-
 #endif
index ca44c71e7fb396a93bcdb0483af52c9fc0900d70..c7000634ccae6900170be103a4b0fd99f571c55b 100644 (file)
@@ -1,21 +1,7 @@
 #ifndef __X86_64_MMU_CONTEXT_H
 #define __X86_64_MMU_CONTEXT_H
 
-#include <asm/desc.h>
-#include <asm/atomic.h>
-#include <asm/pgalloc.h>
 #include <asm/pda.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#ifndef CONFIG_PARAVIRT
-#include <asm-generic/mm_hooks.h>
-#endif
-
-/*
- * possibly do the LDT unload here?
- */
-int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
-void destroy_context(struct mm_struct *mm);
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
@@ -65,8 +51,4 @@ do {                                          \
        asm volatile("movl %0,%%fs"::"r"(0));   \
 } while (0)
 
-#define activate_mm(prev, next)                        \
-       switch_mm((prev), (next), NULL)
-
-
 #endif
index cb2cad0b65a7dded9049d7a2a8db02e6d58562a4..b2298a227567fa24f28bd04de70b0b80b70aaa93 100644 (file)
 extern struct pglist_data *node_data[];
 #define NODE_DATA(nid) (node_data[nid])
 
-#ifdef CONFIG_X86_NUMAQ
-       #include <asm/numaq.h>
-#elif defined(CONFIG_ACPI_SRAT)/* summit or generic arch */
-       #include <asm/srat.h>
-#endif
+#include <asm/numaq.h>
+/* summit or generic arch */
+#include <asm/srat.h>
 
 extern int get_memcfg_numa_flat(void);
 /*
@@ -26,28 +24,20 @@ extern int get_memcfg_numa_flat(void);
  */
 static inline void get_memcfg_numa(void)
 {
-#ifdef CONFIG_X86_NUMAQ
+
        if (get_memcfg_numaq())
                return;
-#elif defined(CONFIG_ACPI_SRAT)
        if (get_memcfg_from_srat())
                return;
-#endif
-
        get_memcfg_numa_flat();
 }
 
 extern int early_pfn_to_nid(unsigned long pfn);
-extern void numa_kva_reserve(void);
 
 #else /* !CONFIG_NUMA */
 
 #define get_memcfg_numa get_memcfg_numa_flat
-#define get_zholes_size(n) (0)
 
-static inline void numa_kva_reserve(void)
-{
-}
 #endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -55,14 +45,14 @@ static inline void numa_kva_reserve(void)
 /*
  * generic node memory support, the following assumptions apply:
  *
- * 1) memory comes in 256Mb contigious chunks which are either present or not
+ * 1) memory comes in 64Mb contigious chunks which are either present or not
  * 2) we will not have more than 64Gb in total
  *
  * for now assume that 64Gb is max amount of RAM for whole system
  *    64Gb / 4096bytes/page = 16777216 pages
  */
 #define MAX_NR_PAGES 16777216
-#define MAX_ELEMENTS 256
+#define MAX_ELEMENTS 1024
 #define PAGES_PER_ELEMENT (MAX_NR_PAGES/MAX_ELEMENTS)
 
 extern s8 physnode_map[];
@@ -87,9 +77,6 @@ static inline int pfn_to_nid(unsigned long pfn)
        __pgdat->node_start_pfn + __pgdat->node_spanned_pages;          \
 })
 
-#ifdef CONFIG_X86_NUMAQ            /* we have contiguous memory on NUMA-Q */
-#define pfn_valid(pfn)          ((pfn) < num_physpages)
-#else
 static inline int pfn_valid(int pfn)
 {
        int nid = pfn_to_nid(pfn);
@@ -98,7 +85,6 @@ static inline int pfn_valid(int pfn)
                return (pfn < node_end_pfn(nid));
        return 0;
 }
-#endif /* CONFIG_X86_NUMAQ */
 
 #endif /* CONFIG_DISCONTIGMEM */
 
index 57a991b9c0530a0f82268853c74a6feb2411b883..b6995e567fcc64edff23e389bfad9ddeb5647508 100644 (file)
@@ -13,6 +13,12 @@ extern int apic_version[MAX_APICS];
 extern u8 apicid_2_node[];
 extern int pic_mode;
 
+#ifdef CONFIG_X86_NUMAQ
+extern int mp_bus_id_to_node[MAX_MP_BUSSES];
+extern int mp_bus_id_to_local[MAX_MP_BUSSES];
+extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
+#endif
+
 #define MAX_APICID 256
 
 #else
@@ -21,26 +27,30 @@ extern int pic_mode;
 /* Each PCI slot may be a combo card with its own bus.  4 IRQ pins per slot. */
 #define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4)
 
+#endif
+
 extern void early_find_smp_config(void);
 extern void early_get_smp_config(void);
 
-#endif
-
 #if defined(CONFIG_MCA) || defined(CONFIG_EISA)
 extern int mp_bus_id_to_type[MAX_MP_BUSSES];
 #endif
 
 extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
 
-extern int mp_bus_id_to_pci_bus[MAX_MP_BUSSES];
-
 extern unsigned int boot_cpu_physical_apicid;
+extern unsigned int max_physical_apicid;
 extern int smp_found_config;
 extern int mpc_default_type;
 extern unsigned long mp_lapic_addr;
 
 extern void find_smp_config(void);
 extern void get_smp_config(void);
+#ifdef CONFIG_X86_MPPARSE
+extern void early_reserve_e820_mpc_new(void);
+#else
+static inline void early_reserve_e820_mpc_new(void) { }
+#endif
 
 void __cpuinit generic_processor_info(int apicid, int version);
 #ifdef CONFIG_ACPI
@@ -49,6 +59,17 @@ 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);
+#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);
+#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
 #endif /* CONFIG_ACPI */
 
 #define PHYSID_ARRAY_SIZE      BITS_TO_LONGS(MAX_APICS)
@@ -101,6 +122,7 @@ typedef struct physid_mask physid_mask_t;
                __physid_mask;                                          \
        })
 
+/* Note: will create very large stack frames if physid_mask_t is big */
 #define physid_mask_of_physid(physid)                                  \
        ({                                                              \
                physid_mask_t __physid_mask = PHYSID_MASK_NONE;         \
@@ -108,6 +130,12 @@ typedef struct physid_mask physid_mask_t;
                __physid_mask;                                          \
        })
 
+static inline void physid_set_mask_of_physid(int physid, physid_mask_t *map)
+{
+       physids_clear(*map);
+       physid_set(physid, *map);
+}
+
 #define PHYSID_MASK_ALL                { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} }
 #define PHYSID_MASK_NONE       { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} }
 
index dc6ef85e362439bc860efe5b3be34136302b206a..38d1e73b49e41ebc1fdd8b07d697697b6b0fff0d 100644 (file)
 # define MAX_MPC_ENTRY 1024
 # define MAX_APICS      256
 #else
-/*
- * A maximum of 255 APICs with the current APIC ID architecture.
- */
-# define MAX_APICS 255
+# if NR_CPUS <= 255
+#  define MAX_APICS     255
+# else
+#  define MAX_APICS   32768
+# endif
 #endif
 
 struct intel_mp_floating {
index 09413ad39d3c8db4aeb42edcedd1a38d6e3779a6..44bce773012e80b11190b7400852f35a55683c98 100644 (file)
 #define MSR_K8_TOP_MEM2                        0xc001001d
 #define MSR_K8_SYSCFG                  0xc0010010
 #define MSR_K8_HWCR                    0xc0010015
-#define MSR_K8_ENABLE_C1E              0xc0010055
+#define MSR_K8_INT_PENDING_MSG         0xc0010055
+/* C1E active bits in int pending message */
+#define K8_INTP_C1E_ACTIVE_MASK                0x18000000
 #define MSR_K8_TSEG_ADDR               0xc0010112
 #define K8_MTRRFIXRANGE_DRAM_ENABLE    0x00040000 /* MtrrFixDramEn bit    */
 #define K8_MTRRFIXRANGE_DRAM_MODIFY    0x00080000 /* MtrrFixDramModEn bit */
index 2b5f2c91db25ce8b3879c6673fa2514cee80b8ce..ca110ee73f074cf41550e7d7860eb412b7bb82ed 100644 (file)
@@ -66,7 +66,7 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
 static inline void native_write_msr(unsigned int msr,
                                    unsigned low, unsigned high)
 {
-       asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high));
+       asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
 }
 
 static inline int native_write_msr_safe(unsigned int msr,
@@ -81,7 +81,8 @@ static inline int native_write_msr_safe(unsigned int msr,
                     _ASM_EXTABLE(2b, 3b)
                     : "=a" (err)
                     : "c" (msr), "0" (low), "d" (high),
-                    "i" (-EFAULT));
+                      "i" (-EFAULT)
+                    : "memory");
        return err;
 }
 
index 1e363021e72fc0dc1dd66977322f10803cf31f1c..21f8d0202a828ee8f6d1bf14b444e2b340f6cb3d 100644 (file)
  */
 int do_nmi_callback(struct pt_regs *regs, int cpu);
 
-#ifdef CONFIG_PM
-
-/** Replace the PM callback routine for NMI. */
-struct pm_dev *set_nmi_pm_callback(pm_callback callback);
-
-/** Unset the PM callback routine back to the default. */
-void unset_nmi_pm_callback(struct pm_dev *dev);
-
-#else
-
-static inline struct pm_dev *set_nmi_pm_callback(pm_callback callback)
-{
-       return 0;
-}
-
-static inline void unset_nmi_pm_callback(struct pm_dev *dev)
-{
-}
-
-#endif /* CONFIG_PM */
-
 #ifdef CONFIG_X86_64
 extern void default_do_nmi(struct pt_regs *);
-extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
-extern void nmi_watchdog_default(void);
-#else
-#define nmi_watchdog_default() do {} while (0)
 #endif
 
+extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int check_nmi_watchdog(void);
 extern int nmi_watchdog_enabled;
-extern int unknown_nmi_panic;
 extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
 extern int avail_to_resrv_perfctr_nmi(unsigned int);
 extern int reserve_perfctr_nmi(unsigned int);
@@ -62,12 +37,10 @@ extern int nmi_watchdog_tick(struct pt_regs *regs, unsigned reason);
 
 extern atomic_t nmi_active;
 extern unsigned int nmi_watchdog;
-#define NMI_DISABLED    -1
 #define NMI_NONE       0
 #define NMI_IO_APIC    1
 #define NMI_LOCAL_APIC 2
 #define NMI_INVALID    3
-#define NMI_DEFAULT    NMI_DISABLED
 
 struct ctl_table;
 struct file;
@@ -78,6 +51,24 @@ extern int unknown_nmi_panic;
 void __trigger_all_cpu_backtrace(void);
 #define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
 
+static inline void localise_nmi_watchdog(void)
+{
+       if (nmi_watchdog == NMI_IO_APIC)
+               nmi_watchdog = NMI_LOCAL_APIC;
+}
+
+/* check if nmi_watchdog is active (ie was specified at boot) */
+static inline int nmi_watchdog_active(void)
+{
+       /*
+        * actually it should be:
+        *      return (nmi_watchdog == NMI_LOCAL_APIC ||
+        *              nmi_watchdog == NMI_IO_APIC)
+        * but since they are power of two we could use a
+        * cheaper way --cvg
+        */
+       return nmi_watchdog & 0x3;
+}
 #endif
 
 void lapic_watchdog_stop(void);
index 03d0f7a9bf0249b9e649605625530ccac9d6f836..220d7b7707a02be8d82232d5395732a6f9a3efa2 100644 (file)
@@ -2,14 +2,10 @@
 #define _ASM_X86_32_NUMA_H 1
 
 extern int pxm_to_nid(int pxm);
+extern void numa_remove_cpu(int cpu);
 
 #ifdef CONFIG_NUMA
-extern void __init remap_numa_kva(void);
-extern void set_highmem_pages_init(int);
-#else
-static inline void remap_numa_kva(void)
-{
-}
+extern void set_highmem_pages_init(void);
 #endif
 
 #endif /* _ASM_X86_32_NUMA_H */
index 22e87c9f6a80551be4ed7108a87a83e4551a15ab..3830094434a9ef75eb686bb2a84ef5c10daaaef7 100644 (file)
@@ -14,32 +14,30 @@ extern int compute_hash_shift(struct bootnode *nodes, int numblks,
 
 #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
 
-extern void numa_add_cpu(int cpu);
 extern void numa_init_array(void);
 extern int numa_off;
 
-extern void numa_set_node(int cpu, int node);
 extern void srat_reserve_add_area(int nodeid);
 extern int hotadd_percent;
 
 extern s16 apicid_to_node[MAX_LOCAL_APIC];
 
-extern void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
 extern unsigned long numa_free_all_bootmem(void);
 extern void setup_node_bootmem(int nodeid, unsigned long start,
                               unsigned long end);
 
 #ifdef CONFIG_NUMA
 extern void __init init_cpu_to_node(void);
-
-static inline void clear_node_cpumask(int cpu)
-{
-       clear_bit(cpu, (unsigned long *)&node_to_cpumask_map[cpu_to_node(cpu)]);
-}
-
+extern void __cpuinit numa_set_node(int cpu, int node);
+extern void __cpuinit numa_clear_node(int cpu);
+extern void __cpuinit numa_add_cpu(int cpu);
+extern void __cpuinit numa_remove_cpu(int cpu);
 #else
-#define init_cpu_to_node() do {} while (0)
-#define clear_node_cpumask(cpu) do {} while (0)
+static inline void init_cpu_to_node(void)              { }
+static inline void numa_set_node(int cpu, int node)    { }
+static inline void numa_clear_node(int cpu)            { }
+static inline void numa_add_cpu(int cpu, int node)     { }
+static inline void numa_remove_cpu(int cpu)            { }
 #endif
 
 #endif
index 94b86c31239aad607ff00e344e67233b42882f82..34b92d581fa326839f7c2568b82d9033472d44dd 100644 (file)
@@ -28,6 +28,7 @@
 
 #ifdef CONFIG_X86_NUMAQ
 
+extern int found_numaq;
 extern int get_memcfg_numaq(void);
 
 /*
@@ -156,9 +157,12 @@ struct sys_cfg_data {
        struct          eachquadmem eq[MAX_NUMNODES];   /* indexed by quad id */
 };
 
-static inline unsigned long *get_zholes_size(int nid)
+void numaq_tsc_disable(void);
+
+#else
+static inline int get_memcfg_numaq(void)
 {
-       return NULL;
+       return 0;
 }
 #endif /* CONFIG_X86_NUMAQ */
 #endif /* NUMAQ_H */
index dc936dddf16118e667f7c074ef5f27fdbfd4dbf8..28d7b4533b1a63fc1c54dc9f69a0db326e3a16f7 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+typedef struct { pgdval_t pgd; } pgd_t;
+typedef struct { pgprotval_t pgprot; } pgprot_t;
+
 extern int page_is_ram(unsigned long pagenr);
 extern int devmem_is_allowed(unsigned long pagenr);
+extern void map_devmem(unsigned long pfn, unsigned long size,
+                      pgprot_t vma_prot);
+extern void unmap_devmem(unsigned long pfn, unsigned long size,
+                        pgprot_t vma_prot);
 
+extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
 struct page;
@@ -74,9 +82,6 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
        alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
 
-typedef struct { pgdval_t pgd; } pgd_t;
-typedef struct { pgprotval_t pgprot; } pgprot_t;
-
 static inline pgd_t native_make_pgd(pgdval_t val)
 {
        return (pgd_t) { val };
@@ -160,6 +165,7 @@ static inline pteval_t native_pte_val(pte_t pte)
 #endif
 
 #define pte_val(x)     native_pte_val(x)
+#define pte_flags(x)   native_pte_val(x)
 #define __pte(x)       native_make_pte(x)
 
 #endif /* CONFIG_PARAVIRT */
index ccf0ba3c3abac74f4329221876987df4b284ac95..ab8528793f081bef8d7c945b7bddbaf1bff54073 100644 (file)
  */
 #define __PAGE_OFFSET          _AC(CONFIG_PAGE_OFFSET, UL)
 
+#ifdef CONFIG_4KSTACKS
+#define THREAD_ORDER   0
+#else
+#define THREAD_ORDER   1
+#endif
+#define THREAD_SIZE    (PAGE_SIZE << THREAD_ORDER)
+
+
 #ifdef CONFIG_X86_PAE
 /* 44=32+12, the limit we can fit into an unsigned long pfn */
 #define __PHYSICAL_MASK_SHIFT  44
@@ -84,6 +92,13 @@ extern int sysctl_legacy_va_layout;
 #define VMALLOC_RESERVE                ((unsigned long)__VMALLOC_RESERVE)
 #define MAXMEM                 (-__PAGE_OFFSET - __VMALLOC_RESERVE)
 
+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 setup_bootmem_allocator(void);
+
+
 #ifdef CONFIG_X86_USE_3DNOW
 #include <asm/mmx.h>
 
index 6ea72859c491abaeec409afcdeb548e1c464192e..c6916c83e6b1aee454e8a8d55ccd787652bee88e 100644 (file)
 #define PUD_PAGE_SIZE          (_AC(1, UL) << PUD_SHIFT)
 #define PUD_PAGE_MASK          (~(PUD_PAGE_SIZE-1))
 
-#define __PAGE_OFFSET           _AC(0xffff810000000000, UL)
+/*
+ * Set __PAGE_OFFSET to the most negative possible address +
+ * PGDIR_SIZE*16 (pgd slot 272).  The gap is to allow a space for a
+ * hypervisor to fit.  Choosing 16 slots here is arbitrary, but it's
+ * what Xen requires.
+ */
+#define __PAGE_OFFSET           _AC(0xffff880000000000, UL)
 
 #define __PHYSICAL_START       CONFIG_PHYSICAL_START
 #define __KERNEL_ALIGN         0x200000
@@ -58,7 +64,8 @@
 void clear_page(void *page);
 void copy_page(void *to, void *from);
 
-extern unsigned long end_pfn;
+/* duplicated to the one in bootmem.h */
+extern unsigned long max_pfn;
 extern unsigned long phys_base;
 
 extern unsigned long __phys_addr(unsigned long);
@@ -83,10 +90,15 @@ typedef struct { pteval_t pte; } pte_t;
 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 init_extra_mapping_uc(unsigned long phys, unsigned long size);
+extern void init_extra_mapping_wb(unsigned long phys, unsigned long size);
+
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_FLATMEM
-#define pfn_valid(pfn)          ((pfn) < end_pfn)
+#define pfn_valid(pfn)          ((pfn) < max_pfn)
 #endif
 
 
index 0f13b945e2400323cb65dfd6f8a7cc5b035c3319..ef5e8ec6a6ab7431f0c799a2b56a4cd5f18fe5e9 100644 (file)
@@ -84,7 +84,7 @@ struct pv_time_ops {
        int (*set_wallclock)(unsigned long);
 
        unsigned long long (*sched_clock)(void);
-       unsigned long (*get_cpu_khz)(void);
+       unsigned long (*get_tsc_khz)(void);
 };
 
 struct pv_cpu_ops {
@@ -115,6 +115,9 @@ struct pv_cpu_ops {
        void (*set_ldt)(const void *desc, unsigned entries);
        unsigned long (*store_tr)(void);
        void (*load_tls)(struct thread_struct *t, unsigned int cpu);
+#ifdef CONFIG_X86_64
+       void (*load_gs_index)(unsigned int idx);
+#endif
        void (*write_ldt_entry)(struct desc_struct *ldt, int entrynum,
                                const void *desc);
        void (*write_gdt_entry)(struct desc_struct *,
@@ -141,8 +144,32 @@ struct pv_cpu_ops {
        u64 (*read_pmc)(int counter);
        unsigned long long (*read_tscp)(unsigned int *aux);
 
-       /* These two are jmp to, not actually called. */
-       void (*irq_enable_syscall_ret)(void);
+       /*
+        * Atomically enable interrupts and return to userspace.  This
+        * is only ever used to return to 32-bit processes; in a
+        * 64-bit kernel, it's used for 32-on-64 compat processes, but
+        * never native 64-bit processes.  (Jump, not call.)
+        */
+       void (*irq_enable_sysexit)(void);
+
+       /*
+        * Switch to usermode gs and return to 64-bit usermode using
+        * sysret.  Only used in 64-bit kernels to return to 64-bit
+        * processes.  Usermode register state, including %rsp, must
+        * already be restored.
+        */
+       void (*usergs_sysret64)(void);
+
+       /*
+        * Switch to usermode gs and return to 32-bit usermode using
+        * sysret.  Used to return to 32-on-64 compat processes.
+        * Other usermode register state, including %esp, must already
+        * be restored.
+        */
+       void (*usergs_sysret32)(void);
+
+       /* Normal iret.  Jump to this with the standard iret stack
+          frame set up. */
        void (*iret)(void);
 
        void (*swapgs)(void);
@@ -165,6 +192,10 @@ struct pv_irq_ops {
        void (*irq_enable)(void);
        void (*safe_halt)(void);
        void (*halt)(void);
+
+#ifdef CONFIG_X86_64
+       void (*adjust_exception_frame)(void);
+#endif
 };
 
 struct pv_apic_ops {
@@ -219,7 +250,14 @@ struct pv_mmu_ops {
        void (*flush_tlb_others)(const cpumask_t *cpus, struct mm_struct *mm,
                                 unsigned long va);
 
-       /* Hooks for allocating/releasing pagetable pages */
+       /* Hooks for allocating and freeing a pagetable top-level */
+       int  (*pgd_alloc)(struct mm_struct *mm);
+       void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd);
+
+       /*
+        * Hooks for allocating/releasing pagetable pages when they're
+        * attached to a pagetable
+        */
        void (*alloc_pte)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pmd)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pmd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
@@ -238,7 +276,13 @@ struct pv_mmu_ops {
        void (*pte_update_defer)(struct mm_struct *mm,
                                 unsigned long addr, pte_t *ptep);
 
+       pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
+                                       pte_t *ptep);
+       void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr,
+                                       pte_t *ptep, pte_t pte);
+
        pteval_t (*pte_val)(pte_t);
+       pteval_t (*pte_flags)(pte_t);
        pte_t (*make_pte)(pteval_t pte);
 
        pgdval_t (*pgd_val)(pgd_t);
@@ -273,6 +317,13 @@ struct pv_mmu_ops {
 #endif
 
        struct pv_lazy_ops lazy_mode;
+
+       /* dom0 ops */
+
+       /* Sometimes the physical address is a pfn, and sometimes its
+          an mfn.  We can tell which is which from the index. */
+       void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
+                          unsigned long phys, pgprot_t flags);
 };
 
 /* This contains all the paravirt structures: we get a convenient
@@ -439,10 +490,17 @@ int paravirt_disable_iospace(void);
 #define VEXTRA_CLOBBERS         , "rax", "r8", "r9", "r10", "r11"
 #endif
 
+#ifdef CONFIG_PARAVIRT_DEBUG
+#define PVOP_TEST_NULL(op)     BUG_ON(op == NULL)
+#else
+#define PVOP_TEST_NULL(op)     ((void)op)
+#endif
+
 #define __PVOP_CALL(rettype, op, pre, post, ...)                       \
        ({                                                              \
                rettype __ret;                                          \
                PVOP_CALL_ARGS;                                 \
+               PVOP_TEST_NULL(op);                                     \
                /* This is 32-bit specific, but is okay in 64-bit */    \
                /* since this condition will never hold */              \
                if (sizeof(rettype) > sizeof(unsigned long)) {          \
@@ -471,6 +529,7 @@ int paravirt_disable_iospace(void);
 #define __PVOP_VCALL(op, pre, post, ...)                               \
        ({                                                              \
                PVOP_VCALL_ARGS;                                        \
+               PVOP_TEST_NULL(op);                                     \
                asm volatile(pre                                        \
                             paravirt_alt(PARAVIRT_CALL)                \
                             post                                       \
@@ -720,7 +779,7 @@ static inline unsigned long long paravirt_sched_clock(void)
 {
        return PVOP_CALL0(unsigned long long, pv_time_ops.sched_clock);
 }
-#define calculate_cpu_khz() (pv_time_ops.get_cpu_khz())
+#define calibrate_tsc() (pv_time_ops.get_tsc_khz())
 
 static inline unsigned long long paravirt_read_pmc(int counter)
 {
@@ -789,6 +848,13 @@ static inline void load_TLS(struct thread_struct *t, unsigned cpu)
        PVOP_VCALL2(pv_cpu_ops.load_tls, t, cpu);
 }
 
+#ifdef CONFIG_X86_64
+static inline void load_gs_index(unsigned int gs)
+{
+       PVOP_VCALL1(pv_cpu_ops.load_gs_index, gs);
+}
+#endif
+
 static inline void write_ldt_entry(struct desc_struct *dt, int entry,
                                   const void *desc)
 {
@@ -912,6 +978,16 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va);
 }
 
+static inline int paravirt_pgd_alloc(struct mm_struct *mm)
+{
+       return PVOP_CALL1(int, pv_mmu_ops.pgd_alloc, mm);
+}
+
+static inline void paravirt_pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+       PVOP_VCALL2(pv_mmu_ops.pgd_free, mm, pgd);
+}
+
 static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned pfn)
 {
        PVOP_VCALL2(pv_mmu_ops.alloc_pte, mm, pfn);
@@ -996,6 +1072,20 @@ static inline pteval_t pte_val(pte_t pte)
        return ret;
 }
 
+static inline pteval_t pte_flags(pte_t pte)
+{
+       pteval_t ret;
+
+       if (sizeof(pteval_t) > sizeof(long))
+               ret = PVOP_CALL2(pteval_t, pv_mmu_ops.pte_flags,
+                                pte.pte, (u64)pte.pte >> 32);
+       else
+               ret = PVOP_CALL1(pteval_t, pv_mmu_ops.pte_flags,
+                                pte.pte);
+
+       return ret;
+}
+
 static inline pgd_t __pgd(pgdval_t val)
 {
        pgdval_t ret;
@@ -1024,6 +1114,29 @@ static inline pgdval_t pgd_val(pgd_t pgd)
        return ret;
 }
 
+#define  __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr,
+                                          pte_t *ptep)
+{
+       pteval_t ret;
+
+       ret = PVOP_CALL3(pteval_t, pv_mmu_ops.ptep_modify_prot_start,
+                        mm, addr, ptep);
+
+       return (pte_t) { .pte = ret };
+}
+
+static inline void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
+                                          pte_t *ptep, pte_t pte)
+{
+       if (sizeof(pteval_t) > sizeof(long))
+               /* 5 arg words */
+               pv_mmu_ops.ptep_modify_prot_commit(mm, addr, ptep, pte);
+       else
+               PVOP_VCALL4(pv_mmu_ops.ptep_modify_prot_commit,
+                           mm, addr, ptep, pte.pte);
+}
+
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
        if (sizeof(pteval_t) > sizeof(long))
@@ -1252,6 +1365,12 @@ static inline void arch_flush_lazy_mmu_mode(void)
        }
 }
 
+static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
+                               unsigned long phys, pgprot_t flags)
+{
+       pv_mmu_ops.set_fixmap(idx, phys, flags);
+}
+
 void _paravirt_nop(void);
 #define paravirt_nop   ((void *)_paravirt_nop)
 
@@ -1374,54 +1493,86 @@ static inline unsigned long __raw_local_irq_save(void)
 #define PV_RESTORE_REGS popq %rdx; popq %rcx; popq %rdi; popq %rax
 #define PARA_PATCH(struct, off)        ((PARAVIRT_PATCH_##struct + (off)) / 8)
 #define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .quad, 8)
+#define PARA_INDIRECT(addr)    *addr(%rip)
 #else
 #define PV_SAVE_REGS   pushl %eax; pushl %edi; pushl %ecx; pushl %edx
 #define PV_RESTORE_REGS popl %edx; popl %ecx; popl %edi; popl %eax
 #define PARA_PATCH(struct, off)        ((PARAVIRT_PATCH_##struct + (off)) / 4)
 #define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .long, 4)
+#define PARA_INDIRECT(addr)    *%cs:addr
 #endif
 
 #define INTERRUPT_RETURN                                               \
        PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_iret), CLBR_NONE,       \
-                 jmp *%cs:pv_cpu_ops+PV_CPU_iret)
+                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret))
 
 #define DISABLE_INTERRUPTS(clobbers)                                   \
        PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_disable), clobbers, \
-                 PV_SAVE_REGS;                 \
-                 call *%cs:pv_irq_ops+PV_IRQ_irq_disable;              \
+                 PV_SAVE_REGS;                                         \
+                 call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_disable);    \
                  PV_RESTORE_REGS;)                     \
 
 #define ENABLE_INTERRUPTS(clobbers)                                    \
        PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_enable), clobbers,  \
-                 PV_SAVE_REGS;                 \
-                 call *%cs:pv_irq_ops+PV_IRQ_irq_enable;               \
+                 PV_SAVE_REGS;                                         \
+                 call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable);     \
                  PV_RESTORE_REGS;)
 
-#define ENABLE_INTERRUPTS_SYSCALL_RET                                  \
-       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_syscall_ret),\
+#define USERGS_SYSRET32                                                        \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret32),       \
                  CLBR_NONE,                                            \
-                 jmp *%cs:pv_cpu_ops+PV_CPU_irq_enable_syscall_ret)
-
+                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret32))
 
 #ifdef CONFIG_X86_32
-#define GET_CR0_INTO_EAX                       \
-       push %ecx; push %edx;                   \
-       call *pv_cpu_ops+PV_CPU_read_cr0;       \
+#define GET_CR0_INTO_EAX                               \
+       push %ecx; push %edx;                           \
+       call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \
        pop %edx; pop %ecx
-#else
+
+#define ENABLE_INTERRUPTS_SYSEXIT                                      \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit),    \
+                 CLBR_NONE,                                            \
+                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit))
+
+
+#else  /* !CONFIG_X86_32 */
+
+/*
+ * If swapgs is used while the userspace stack is still current,
+ * there's no way to call a pvop.  The PV replacement *must* be
+ * inlined, or the swapgs instruction must be trapped and emulated.
+ */
+#define SWAPGS_UNSAFE_STACK                                            \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE,     \
+                 swapgs)
+
 #define SWAPGS                                                         \
        PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE,     \
                  PV_SAVE_REGS;                                         \
-                 call *pv_cpu_ops+PV_CPU_swapgs;                       \
+                 call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs);         \
                  PV_RESTORE_REGS                                       \
                 )
 
-#define GET_CR2_INTO_RCX                       \
-       call *pv_mmu_ops+PV_MMU_read_cr2;       \
-       movq %rax, %rcx;                        \
+#define GET_CR2_INTO_RCX                               \
+       call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2); \
+       movq %rax, %rcx;                                \
        xorq %rax, %rax;
 
-#endif
+#define PARAVIRT_ADJUST_EXCEPTION_FRAME                                        \
+       PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \
+                 CLBR_NONE,                                            \
+                 call PARA_INDIRECT(pv_irq_ops+PV_IRQ_adjust_exception_frame))
+
+#define USERGS_SYSRET64                                                        \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64),       \
+                 CLBR_NONE,                                            \
+                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64))
+
+#define ENABLE_INTERRUPTS_SYSEXIT32                                    \
+       PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit),    \
+                 CLBR_NONE,                                            \
+                 jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit))
+#endif /* CONFIG_X86_32 */
 
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_PARAVIRT */
index 88f60cc6a22737f8e45b20e36a67b27410bb5326..7edc473072179c48defd9043a2ec5be0202dbbcf 100644 (file)
@@ -1,14 +1,13 @@
-
 #ifndef _ASM_PAT_H
-#define _ASM_PAT_H 1
+#define _ASM_PAT_H
 
 #include <linux/types.h>
 
 #ifdef CONFIG_X86_PAT
-extern int pat_wc_enabled;
+extern int pat_enabled;
 extern void validate_pat_support(struct cpuinfo_x86 *c);
 #else
-static const int pat_wc_enabled = 0;
+static const int pat_enabled;
 static inline void validate_pat_support(struct cpuinfo_x86 *c) { }
 #endif
 
@@ -21,4 +20,3 @@ extern int free_memtype(u64 start, u64 end);
 extern void pat_disable(char *reason);
 
 #endif
-
index 30bbde0cb34bfba7e272ad68be2dffad8ef20d0d..2db14cf17db8f9faeae76133445f144023d58ff6 100644 (file)
@@ -18,6 +18,8 @@ struct pci_sysdata {
 #endif
 };
 
+extern int pci_routeirq;
+
 /* scan a bus after allocating a pci_sysdata for it */
 extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
                                            int node);
index 8c4c3a0368e27735eebbc8553cfa7decd67734fb..a50d468512857e2dd9cbdecf3b76fd986e15b1d4 100644 (file)
@@ -18,12 +18,14 @@ struct pci_dev;
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
 /* pci_unmap_{page,single} is a nop so... */
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
-#define pci_unmap_addr(PTR, ADDR_NAME)         (0)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)        do { } while (0)
-#define pci_unmap_len(PTR, LEN_NAME)           (0)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)  do { } while (0)
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      dma_addr_t ADDR_NAME[0];
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)        unsigned LEN_NAME[0];
+#define pci_unmap_addr(PTR, ADDR_NAME) sizeof((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
+       do { break; } while (pci_unmap_addr(PTR, ADDR_NAME))
+#define pci_unmap_len(PTR, LEN_NAME)           sizeof((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
+       do { break; } while (pci_unmap_len(PTR, LEN_NAME))
 
 
 #endif /* __KERNEL__ */
index 101fb9e11954e8bd45c21a4524c5c8c8f9019132..b34e9a7cc80b3002dc9e331f224298d8754482f1 100644 (file)
@@ -22,6 +22,8 @@ struct x8664_pda {
                                           offset 40!!! */
 #endif
        char *irqstackptr;
+       short nodenumber;               /* number of current node (32k max) */
+       short in_bootmem;               /* pda lives in bootmem */
        unsigned int __softirq_pending;
        unsigned int __nmi_count;       /* number of NMI on this CPUs */
        short mmu_state;
@@ -37,8 +39,7 @@ struct x8664_pda {
        unsigned irq_spurious_count;
 } ____cacheline_aligned_in_smp;
 
-extern struct x8664_pda *_cpu_pda[];
-extern struct x8664_pda boot_cpu_pda[];
+extern struct x8664_pda **_cpu_pda;
 extern void pda_init(int);
 
 #define cpu_pda(i) (_cpu_pda[i])
index 736fc3bb8e1eaa1f8280ed471c70c6deffe20512..912a3a17b9db85958abee1464d58e64d798f5f31 100644 (file)
@@ -143,4 +143,50 @@ do {                                                       \
 #define x86_or_percpu(var, val) percpu_to_op("or", per_cpu__##var, val)
 #endif /* !__ASSEMBLY__ */
 #endif /* !CONFIG_X86_64 */
+
+#ifdef CONFIG_SMP
+
+/*
+ * Define the "EARLY_PER_CPU" macros.  These are used for some per_cpu
+ * variables that are initialized and accessed before there are per_cpu
+ * areas allocated.
+ */
+
+#define        DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)                  \
+       DEFINE_PER_CPU(_type, _name) = _initvalue;                      \
+       __typeof__(_type) _name##_early_map[NR_CPUS] __initdata =       \
+                               { [0 ... NR_CPUS-1] = _initvalue };     \
+       __typeof__(_type) *_name##_early_ptr = _name##_early_map
+
+#define EXPORT_EARLY_PER_CPU_SYMBOL(_name)                     \
+       EXPORT_PER_CPU_SYMBOL(_name)
+
+#define DECLARE_EARLY_PER_CPU(_type, _name)                    \
+       DECLARE_PER_CPU(_type, _name);                          \
+       extern __typeof__(_type) *_name##_early_ptr;            \
+       extern __typeof__(_type)  _name##_early_map[]
+
+#define        early_per_cpu_ptr(_name) (_name##_early_ptr)
+#define        early_per_cpu_map(_name, _idx) (_name##_early_map[_idx])
+#define        early_per_cpu(_name, _cpu)                              \
+       (early_per_cpu_ptr(_name) ?                             \
+               early_per_cpu_ptr(_name)[_cpu] :                \
+               per_cpu(_name, _cpu))
+
+#else  /* !CONFIG_SMP */
+#define        DEFINE_EARLY_PER_CPU(_type, _name, _initvalue)          \
+       DEFINE_PER_CPU(_type, _name) = _initvalue
+
+#define EXPORT_EARLY_PER_CPU_SYMBOL(_name)                     \
+       EXPORT_PER_CPU_SYMBOL(_name)
+
+#define DECLARE_EARLY_PER_CPU(_type, _name)                    \
+       DECLARE_PER_CPU(_type, _name)
+
+#define        early_per_cpu(_name, _cpu) per_cpu(_name, _cpu)
+#define        early_per_cpu_ptr(_name) NULL
+/* no early_per_cpu_map() */
+
+#endif /* !CONFIG_SMP */
+
 #endif /* _ASM_X86_PERCPU_H_ */
index 91e4641f3f319de6072c63b436c17fb252c9e5b6..d63ea431cb3bbc974bec3fa3b22e5afff0194c17 100644 (file)
@@ -5,9 +5,13 @@
 #include <linux/mm.h>          /* for struct page */
 #include <linux/pagemap.h>
 
+static inline int  __paravirt_pgd_alloc(struct mm_struct *mm) { return 0; }
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
+#define paravirt_pgd_alloc(mm) __paravirt_pgd_alloc(mm)
+static inline void paravirt_pgd_free(struct mm_struct *mm, pgd_t *pgd) {}
 static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned long pfn) {}
 static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn) {}
 static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,
index 97c271b2910b3266b4aaafa53385dfd8148bf374..49cbd76b9547ed3d0bf3075f4f6980a0143858c7 100644 (file)
 #define _PAGE_BIT_PAT_LARGE    12      /* On 2MB or 1GB pages */
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
-/*
- * Note: we use _AC(1, L) instead of _AC(1, UL) so that we get a
- * sign-extended value on 32-bit with all 1's in the upper word,
- * which preserves the upper pte values on 64-bit ptes:
- */
-#define _PAGE_PRESENT  (_AC(1, L)<<_PAGE_BIT_PRESENT)
-#define _PAGE_RW       (_AC(1, L)<<_PAGE_BIT_RW)
-#define _PAGE_USER     (_AC(1, L)<<_PAGE_BIT_USER)
-#define _PAGE_PWT      (_AC(1, L)<<_PAGE_BIT_PWT)
-#define _PAGE_PCD      (_AC(1, L)<<_PAGE_BIT_PCD)
-#define _PAGE_ACCESSED (_AC(1, L)<<_PAGE_BIT_ACCESSED)
-#define _PAGE_DIRTY    (_AC(1, L)<<_PAGE_BIT_DIRTY)
-#define _PAGE_PSE      (_AC(1, L)<<_PAGE_BIT_PSE)      /* 2MB page */
-#define _PAGE_GLOBAL   (_AC(1, L)<<_PAGE_BIT_GLOBAL)   /* Global TLB entry */
-#define _PAGE_UNUSED1  (_AC(1, L)<<_PAGE_BIT_UNUSED1)
-#define _PAGE_UNUSED2  (_AC(1, L)<<_PAGE_BIT_UNUSED2)
-#define _PAGE_UNUSED3  (_AC(1, L)<<_PAGE_BIT_UNUSED3)
-#define _PAGE_PAT      (_AC(1, L)<<_PAGE_BIT_PAT)
-#define _PAGE_PAT_LARGE (_AC(1, L)<<_PAGE_BIT_PAT_LARGE)
+#define _PAGE_PRESENT  (_AT(pteval_t, 1) << _PAGE_BIT_PRESENT)
+#define _PAGE_RW       (_AT(pteval_t, 1) << _PAGE_BIT_RW)
+#define _PAGE_USER     (_AT(pteval_t, 1) << _PAGE_BIT_USER)
+#define _PAGE_PWT      (_AT(pteval_t, 1) << _PAGE_BIT_PWT)
+#define _PAGE_PCD      (_AT(pteval_t, 1) << _PAGE_BIT_PCD)
+#define _PAGE_ACCESSED (_AT(pteval_t, 1) << _PAGE_BIT_ACCESSED)
+#define _PAGE_DIRTY    (_AT(pteval_t, 1) << _PAGE_BIT_DIRTY)
+#define _PAGE_PSE      (_AT(pteval_t, 1) << _PAGE_BIT_PSE)
+#define _PAGE_GLOBAL   (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
+#define _PAGE_UNUSED1  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1)
+#define _PAGE_UNUSED2  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED2)
+#define _PAGE_UNUSED3  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3)
+#define _PAGE_PAT      (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
+#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
 
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
-#define _PAGE_NX       (_AC(1, ULL) << _PAGE_BIT_NX)
+#define _PAGE_NX       (_AT(pteval_t, 1) << _PAGE_BIT_NX)
 #else
-#define _PAGE_NX       0
+#define _PAGE_NX       (_AT(pteval_t, 0))
 #endif
 
 /* If _PAGE_PRESENT is clear, we use these: */
 #define PAGE_READONLY_EXEC     __pgprot(_PAGE_PRESENT | _PAGE_USER |   \
                                         _PAGE_ACCESSED)
 
-#ifdef CONFIG_X86_32
-#define _PAGE_KERNEL_EXEC \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define _PAGE_KERNEL (_PAGE_KERNEL_EXEC | _PAGE_NX)
-
-#ifndef __ASSEMBLY__
-extern pteval_t __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
-#endif /* __ASSEMBLY__ */
-#else
 #define __PAGE_KERNEL_EXEC                                             \
-       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+       (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_GLOBAL)
 #define __PAGE_KERNEL          (__PAGE_KERNEL_EXEC | _PAGE_NX)
-#endif
 
 #define __PAGE_KERNEL_RO               (__PAGE_KERNEL & ~_PAGE_RW)
 #define __PAGE_KERNEL_RX               (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
@@ -106,26 +91,22 @@ extern pteval_t __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 #define __PAGE_KERNEL_VSYSCALL         (__PAGE_KERNEL_RX | _PAGE_USER)
 #define __PAGE_KERNEL_VSYSCALL_NOCACHE (__PAGE_KERNEL_VSYSCALL | _PAGE_PCD | _PAGE_PWT)
 #define __PAGE_KERNEL_LARGE            (__PAGE_KERNEL | _PAGE_PSE)
+#define __PAGE_KERNEL_LARGE_NOCACHE    (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
 #define __PAGE_KERNEL_LARGE_EXEC       (__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
-#ifdef CONFIG_X86_32
-# define MAKE_GLOBAL(x)                        __pgprot((x))
-#else
-# define MAKE_GLOBAL(x)                        __pgprot((x) | _PAGE_GLOBAL)
-#endif
-
-#define PAGE_KERNEL                    MAKE_GLOBAL(__PAGE_KERNEL)
-#define PAGE_KERNEL_RO                 MAKE_GLOBAL(__PAGE_KERNEL_RO)
-#define PAGE_KERNEL_EXEC               MAKE_GLOBAL(__PAGE_KERNEL_EXEC)
-#define PAGE_KERNEL_RX                 MAKE_GLOBAL(__PAGE_KERNEL_RX)
-#define PAGE_KERNEL_WC                 MAKE_GLOBAL(__PAGE_KERNEL_WC)
-#define PAGE_KERNEL_NOCACHE            MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
-#define PAGE_KERNEL_UC_MINUS           MAKE_GLOBAL(__PAGE_KERNEL_UC_MINUS)
-#define PAGE_KERNEL_EXEC_NOCACHE       MAKE_GLOBAL(__PAGE_KERNEL_EXEC_NOCACHE)
-#define PAGE_KERNEL_LARGE              MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
-#define PAGE_KERNEL_LARGE_EXEC         MAKE_GLOBAL(__PAGE_KERNEL_LARGE_EXEC)
-#define PAGE_KERNEL_VSYSCALL           MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
-#define PAGE_KERNEL_VSYSCALL_NOCACHE   MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL_NOCACHE)
+#define PAGE_KERNEL                    __pgprot(__PAGE_KERNEL)
+#define PAGE_KERNEL_RO                 __pgprot(__PAGE_KERNEL_RO)
+#define PAGE_KERNEL_EXEC               __pgprot(__PAGE_KERNEL_EXEC)
+#define PAGE_KERNEL_RX                 __pgprot(__PAGE_KERNEL_RX)
+#define PAGE_KERNEL_WC                 __pgprot(__PAGE_KERNEL_WC)
+#define PAGE_KERNEL_NOCACHE            __pgprot(__PAGE_KERNEL_NOCACHE)
+#define PAGE_KERNEL_UC_MINUS           __pgprot(__PAGE_KERNEL_UC_MINUS)
+#define PAGE_KERNEL_EXEC_NOCACHE       __pgprot(__PAGE_KERNEL_EXEC_NOCACHE)
+#define PAGE_KERNEL_LARGE              __pgprot(__PAGE_KERNEL_LARGE)
+#define PAGE_KERNEL_LARGE_NOCACHE      __pgprot(__PAGE_KERNEL_LARGE_NOCACHE)
+#define PAGE_KERNEL_LARGE_EXEC         __pgprot(__PAGE_KERNEL_LARGE_EXEC)
+#define PAGE_KERNEL_VSYSCALL           __pgprot(__PAGE_KERNEL_VSYSCALL)
+#define PAGE_KERNEL_VSYSCALL_NOCACHE   __pgprot(__PAGE_KERNEL_VSYSCALL_NOCACHE)
 
 /*         xwr */
 #define __P000 PAGE_NONE
@@ -164,37 +145,37 @@ extern struct list_head pgd_list;
  */
 static inline int pte_dirty(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_DIRTY;
+       return pte_flags(pte) & _PAGE_DIRTY;
 }
 
 static inline int pte_young(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_ACCESSED;
+       return pte_flags(pte) & _PAGE_ACCESSED;
 }
 
 static inline int pte_write(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_RW;
+       return pte_flags(pte) & _PAGE_RW;
 }
 
 static inline int pte_file(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_FILE;
+       return pte_flags(pte) & _PAGE_FILE;
 }
 
 static inline int pte_huge(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_PSE;
+       return pte_flags(pte) & _PAGE_PSE;
 }
 
 static inline int pte_global(pte_t pte)
 {
-       return pte_val(pte) & _PAGE_GLOBAL;
+       return pte_flags(pte) & _PAGE_GLOBAL;
 }
 
 static inline int pte_exec(pte_t pte)
 {
-       return !(pte_val(pte) & _PAGE_NX);
+       return !(pte_flags(pte) & _PAGE_NX);
 }
 
 static inline int pte_special(pte_t pte)
@@ -210,22 +191,22 @@ static inline int pmd_large(pmd_t pte)
 
 static inline pte_t pte_mkclean(pte_t pte)
 {
-       return __pte(pte_val(pte) & ~(pteval_t)_PAGE_DIRTY);
+       return __pte(pte_val(pte) & ~_PAGE_DIRTY);
 }
 
 static inline pte_t pte_mkold(pte_t pte)
 {
-       return __pte(pte_val(pte) & ~(pteval_t)_PAGE_ACCESSED);
+       return __pte(pte_val(pte) & ~_PAGE_ACCESSED);
 }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
-       return __pte(pte_val(pte) & ~(pteval_t)_PAGE_RW);
+       return __pte(pte_val(pte) & ~_PAGE_RW);
 }
 
 static inline pte_t pte_mkexec(pte_t pte)
 {
-       return __pte(pte_val(pte) & ~(pteval_t)_PAGE_NX);
+       return __pte(pte_val(pte) & ~_PAGE_NX);
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
@@ -250,7 +231,7 @@ static inline pte_t pte_mkhuge(pte_t pte)
 
 static inline pte_t pte_clrhuge(pte_t pte)
 {
-       return __pte(pte_val(pte) & ~(pteval_t)_PAGE_PSE);
+       return __pte(pte_val(pte) & ~_PAGE_PSE);
 }
 
 static inline pte_t pte_mkglobal(pte_t pte)
@@ -260,7 +241,7 @@ static inline pte_t pte_mkglobal(pte_t pte)
 
 static inline pte_t pte_clrglobal(pte_t pte)
 {
-       return __pte(pte_val(pte) & ~(pteval_t)_PAGE_GLOBAL);
+       return __pte(pte_val(pte) & ~_PAGE_GLOBAL);
 }
 
 static inline pte_t pte_mkspecial(pte_t pte)
@@ -305,7 +286,7 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
        return __pgprot(preservebits | addbits);
 }
 
-#define pte_pgprot(x) __pgprot(pte_val(x) & ~PTE_MASK)
+#define pte_pgprot(x) __pgprot(pte_flags(x) & ~PTE_MASK)
 
 #define canon_pgprot(p) __pgprot(pgprot_val(p) & __supported_pte_mask)
 
@@ -318,6 +299,9 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
                               unsigned long size, pgprot_t *vma_prot);
 #endif
 
+/* Install a pte for a particular vaddr in kernel space. */
+void set_pte_vaddr(unsigned long vaddr, pte_t pte);
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else  /* !CONFIG_PARAVIRT */
@@ -359,6 +343,26 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
 # include "pgtable_64.h"
 #endif
 
+/*
+ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
+ *
+ * this macro returns the index of the entry in the pgd page which would
+ * control the given virtual address
+ */
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+
+/*
+ * pgd_offset() returns a (pgd_t *)
+ * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
+ */
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index((address)))
+/*
+ * a shortcut which implies the use of the kernel's pgd, instead
+ * of a process's
+ */
+#define pgd_offset_k(address) pgd_offset(&init_mm, (address))
+
+
 #define KERNEL_PGD_BOUNDARY    pgd_index(PAGE_OFFSET)
 #define KERNEL_PGD_PTRS                (PTRS_PER_PGD - KERNEL_PGD_BOUNDARY)
 
@@ -369,8 +373,15 @@ enum {
        PG_LEVEL_4K,
        PG_LEVEL_2M,
        PG_LEVEL_1G,
+       PG_LEVEL_NUM
 };
 
+#ifdef CONFIG_PROC_FS
+extern void update_page_count(int level, unsigned long pages);
+#else
+static inline void update_page_count(int level, unsigned long pages) { }
+#endif
+
 /*
  * Helper function that returns the kernel pagetable entry controlling
  * the virtual address 'address'. NULL means no pagetable entry present.
@@ -420,6 +431,8 @@ static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
  * race with other CPU's that might be updating the dirty
  * bit at the same time.
  */
+struct vm_area_struct;
+
 #define  __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 extern int ptep_set_access_flags(struct vm_area_struct *vma,
                                 unsigned long address, pte_t *ptep,
index 32ca03109a4c5f0f6e222cea946f3141bcbca796..ec871c420d7e5c511a41c098c3ffb9895de25a20 100644 (file)
@@ -113,26 +113,6 @@ extern unsigned long pg0[];
  */
 #define mk_pte(page, pgprot)   pfn_pte(page_to_pfn(page), (pgprot))
 
-/*
- * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
- *
- * this macro returns the index of the entry in the pgd page which would
- * control the given virtual address
- */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
-#define pgd_index_k(addr) pgd_index((addr))
-
-/*
- * pgd_offset() returns a (pgd_t *)
- * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
- */
-#define pgd_offset(mm, address) ((mm)->pgd + pgd_index((address)))
-
-/*
- * a shortcut which implies the use of the kernel's pgd, instead
- * of a process's
- */
-#define pgd_offset_k(address) pgd_offset(&init_mm, (address))
 
 static inline int pud_large(pud_t pud) { return 0; }
 
index 1cc50d22d735388f9bb74a11f0765e4d6a1d2472..fa7208b483cada7c9d735f8381c503b289a02d86 100644 (file)
@@ -70,6 +70,9 @@ extern void paging_init(void);
 
 struct mm_struct;
 
+void set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte);
+
+
 static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr,
                                    pte_t *ptep)
 {
@@ -190,12 +193,9 @@ static inline int pmd_bad(pmd_t pmd)
 #define pgd_page_vaddr(pgd)                                            \
        ((unsigned long)__va((unsigned long)pgd_val((pgd)) & PTE_MASK))
 #define pgd_page(pgd)          (pfn_to_page(pgd_val((pgd)) >> PAGE_SHIFT))
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
-#define pgd_offset(mm, address)        ((mm)->pgd + pgd_index((address)))
-#define pgd_offset_k(address) (init_level4_pgt + pgd_index((address)))
 #define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT)
 static inline int pgd_large(pgd_t pgd) { return 0; }
-#define mk_kernel_pgd(address) ((pgd_t){ (address) | _KERNPG_TABLE })
+#define mk_kernel_pgd(address) __pgd((address) | _KERNPG_TABLE)
 
 /* PUD - Level3 access */
 /* to find an entry in a page-table-directory. */
index 199cab107d85d134d697dcc3b6ab4227513a2bb9..092b39b3a7e691588de38e4b3a44f2cf76f5051e 100644 (file)
 #define CX86_ARR_BASE  0xc4
 #define CX86_RCR_BASE  0xdc
 
+#ifdef CONFIG_VM86
+#define X86_VM_MASK    X86_EFLAGS_VM
+#else
+#define X86_VM_MASK    0 /* No VM86 support */
+#endif
+
 #endif /* __ASM_I386_PROCESSOR_FLAGS_H */
index 559105220a477e2be9cfbd87eee62d1cd68767c2..7f738270459276a305758ac8a3edce974b1985ba 100644 (file)
@@ -153,7 +153,7 @@ static inline int hlt_works(int cpu)
 
 extern void cpu_detect(struct cpuinfo_x86 *c);
 
-extern void identify_cpu(struct cpuinfo_x86 *);
+extern void early_cpu_init(void);
 extern void identify_boot_cpu(void);
 extern void identify_secondary_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
@@ -262,16 +262,12 @@ struct tss_struct {
        unsigned long           io_bitmap_max;
        struct thread_struct    *io_bitmap_owner;
 
-       /*
-        * Pad the TSS to be cacheline-aligned (size is 0x100):
-        */
-       unsigned long           __cacheline_filler[35];
        /*
         * .. and then another 0x100 bytes for the emergency kernel stack:
         */
        unsigned long           stack[64];
 
-} __attribute__((packed));
+} ____cacheline_aligned;
 
 DECLARE_PER_CPU(struct tss_struct, init_tss);
 
@@ -535,7 +531,6 @@ static inline void load_sp0(struct tss_struct *tss,
 }
 
 #define set_iopl_mask native_set_iopl_mask
-#define SWAPGS swapgs
 #endif /* CONFIG_PARAVIRT */
 
 /*
index 6c8b41b03f6def5593696d12752c3627028e10b3..3dd458c385c0532b59ce3aac67386ad215665dc9 100644 (file)
@@ -14,8 +14,6 @@ extern void ia32_syscall(void);
 extern void ia32_cstar_target(void);
 extern void ia32_sysenter_target(void);
 
-extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
-
 extern void syscall32_cpu_init(void);
 
 extern void check_efer(void);
index 9f922b0b95d6d3961275c9cac804acf22cbb8ef6..8a71db803da6666bf030223503e0dcebf2778efd 100644 (file)
@@ -3,7 +3,12 @@
 
 #include <linux/compiler.h>    /* For __user */
 #include <asm/ptrace-abi.h>
+#include <asm/processor-flags.h>
 
+#ifdef __KERNEL__
+#include <asm/ds.h>            /* the DS BTS struct is used for ptrace too */
+#include <asm/segment.h>
+#endif
 
 #ifndef __ASSEMBLY__
 
@@ -55,9 +60,6 @@ struct pt_regs {
        unsigned long ss;
 };
 
-#include <asm/vm86.h>
-#include <asm/segment.h>
-
 #endif /* __KERNEL__ */
 
 #else /* __i386__ */
index e63741f19392e24d587b3383c18e6de2da1dab18..206f355786dc5651b11777305974b281bb7a4e9f 100644 (file)
@@ -14,8 +14,8 @@ struct machine_ops {
 
 extern struct machine_ops machine_ops;
 
-void machine_real_restart(unsigned char *code, int length);
 void native_machine_crash_shutdown(struct pt_regs *regs);
 void native_machine_shutdown(void);
+void machine_real_restart(const unsigned char *code, int length);
 
 #endif /* _ASM_REBOOT_H */
index 7400d3ad75c6835233c01d51e4351ecf0a3e8636..adec887dd7cd5f07c1148f8c233e033e05160e40 100644 (file)
 
 #if defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64)
 # define NEED_PAE      (1<<(X86_FEATURE_PAE & 31))
-# define NEED_CX8      (1<<(X86_FEATURE_CX8 & 31))
 #else
 # define NEED_PAE      0
+#endif
+
+#ifdef CONFIG_X86_CMPXCHG64
+# define NEED_CX8      (1<<(X86_FEATURE_CX8 & 31))
+#else
 # define NEED_CX8      0
 #endif
 
@@ -38,7 +42,7 @@
 #endif
 
 #ifdef CONFIG_X86_64
-#define NEED_PSE       (1<<(X86_FEATURE_PSE & 31))
+#define NEED_PSE       0
 #define NEED_MSR       (1<<(X86_FEATURE_MSR & 31))
 #define NEED_PGE       (1<<(X86_FEATURE_PGE & 31))
 #define NEED_FXSR      (1<<(X86_FEATURE_FXSR & 31))
index 2557514d7ef646cc066d976b1805b141fc685f83..8d9f0b41ee86ca40f7f9b19d02f43c76348e1069 100644 (file)
@@ -6,7 +6,7 @@
 #define TRACE_RESUME(user)                                     \
 do {                                                           \
        if (pm_trace_enabled) {                                 \
-               void *tracedata;                                \
+               const void *tracedata;                          \
                asm volatile(_ASM_MOV_UL " $1f,%0\n"            \
                             ".section .tracedata,\"a\"\n"      \
                             "1:\t.word %c1\n\t"                \
index 18da19e89bff29088495a9d183d1fb37b788b758..36e71c5f306f0d29d23e7856af34cf46bfc7238c 100644 (file)
@@ -1,4 +1,5 @@
 #ifndef _ASM_SECCOMP_H
+#define _ASM_SECCOMP_H
 
 #include <linux/thread_info.h>
 
index 553af65a2287aa19e9a60f0f2c658e7a5a0d9433..76cfe69aa63c655d969fd80994193697637326bc 100644 (file)
@@ -1,4 +1,5 @@
 #ifndef _ASM_SECCOMP_H
+#define _ASM_SECCOMP_H
 
 #include <linux/thread_info.h>
 
index ed5131dd7d92af9980f34341aed73bbe2eaa340d..dfc8601c08922f26e6b19a4a28d998a0b1a7c274 100644 (file)
 #define GDT_ENTRY_TLS_MAX      (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
 
 #define GDT_ENTRY_DEFAULT_USER_CS      14
-#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)
 
 #define GDT_ENTRY_DEFAULT_USER_DS      15
-#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3)
 
 #define GDT_ENTRY_KERNEL_BASE  12
 
 #define GDT_ENTRY_KERNEL_CS            (GDT_ENTRY_KERNEL_BASE + 0)
-#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)
 
 #define GDT_ENTRY_KERNEL_DS            (GDT_ENTRY_KERNEL_BASE + 1)
-#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)
 
 #define GDT_ENTRY_TSS                  (GDT_ENTRY_KERNEL_BASE + 4)
 #define GDT_ENTRY_LDT                  (GDT_ENTRY_KERNEL_BASE + 5)
 #else
 #include <asm/cache.h>
 
-#define __KERNEL_CS    0x10
-#define __KERNEL_DS    0x18
+#define GDT_ENTRY_KERNEL32_CS 1
+#define GDT_ENTRY_KERNEL_CS 2
+#define GDT_ENTRY_KERNEL_DS 3
 
-#define __KERNEL32_CS   0x08
+#define __KERNEL32_CS   (GDT_ENTRY_KERNEL32_CS * 8)
 
 /*
  * we cannot use the same code segment descriptor for user and kernel
  * The segment offset needs to contain a RPL. Grr. -AK
  * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets)
  */
-
-#define __USER32_CS   0x23   /* 4*8+3 */
-#define __USER_DS     0x2b   /* 5*8+3 */
-#define __USER_CS     0x33   /* 6*8+3 */
+#define GDT_ENTRY_DEFAULT_USER32_CS 4
+#define GDT_ENTRY_DEFAULT_USER_DS 5
+#define GDT_ENTRY_DEFAULT_USER_CS 6
+#define __USER32_CS   (GDT_ENTRY_DEFAULT_USER32_CS * 8 + 3)
 #define __USER32_DS    __USER_DS
 
 #define GDT_ENTRY_TSS 8        /* needs two entries */
 
 #endif
 
+#define __KERNEL_CS    (GDT_ENTRY_KERNEL_CS * 8)
+#define __KERNEL_DS    (GDT_ENTRY_KERNEL_DS * 8)
+#define __USER_DS     (GDT_ENTRY_DEFAULT_USER_DS* 8 + 3)
+#define __USER_CS     (GDT_ENTRY_DEFAULT_USER_CS* 8 + 3)
 #ifndef CONFIG_PARAVIRT
 #define get_kernel_rpl()  0
 #endif
index fa6763af8d2686c8d1b52a023f72c70806ec5bc4..90ab2225e71bbefe9fb06c9d85127c555e8a8445 100644 (file)
@@ -8,7 +8,25 @@
 /* Interrupt control for vSMPowered x86_64 systems */
 void vsmp_init(void);
 
-char *machine_specific_memory_setup(void);
+#ifdef CONFIG_X86_VISWS
+extern void visws_early_detect(void);
+extern int is_visws_box(void);
+#else
+static inline void visws_early_detect(void) { }
+static inline int is_visws_box(void) { return 0; }
+#endif
+
+/*
+ * Any setup quirks to be performed?
+ */
+extern int (*arch_time_init_quirk)(void);
+extern int (*arch_pre_intr_init_quirk)(void);
+extern int (*arch_intr_init_quirk)(void);
+extern int (*arch_trap_init_quirk)(void);
+extern char * (*arch_memory_setup_quirk)(void);
+extern int (*mach_get_smp_config_quirk)(unsigned int early);
+extern int (*mach_find_smp_config_quirk)(unsigned int reserve);
+
 #ifndef CONFIG_PARAVIRT
 #define paravirt_post_allocator_init() do {} while (0)
 #endif
@@ -43,26 +61,23 @@ char *machine_specific_memory_setup(void);
  */
 extern struct boot_params boot_params;
 
-#ifdef __i386__
 /*
  * Do NOT EVER look at the BIOS memory size location.
  * It does not work on many machines.
  */
 #define LOWMEMSIZE()   (0x9f000)
 
-struct e820entry;
-
-char * __init machine_specific_memory_setup(void);
-char *memory_setup(void);
+#ifdef __i386__
 
-int __init copy_e820_map(struct e820entry *biosmap, int nr_map);
-int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map);
-void __init add_memory_region(unsigned long long start,
-                             unsigned long long size, int type);
+void __init i386_start_kernel(void);
+extern void probe_roms(void);
 
+extern unsigned long init_pg_tables_start;
 extern unsigned long init_pg_tables_end;
 
-
+#else
+void __init x86_64_start_kernel(char *real_mode);
+void __init x86_64_start_reservations(char *real_mode_data);
 
 #endif /* __i386__ */
 #endif /* _SETUP */
index 1ebaa5cd31128eb40a7ca2c918aa17d7d8d8f244..2e221f1ce0b21a4ed5cc8c715332455496f34b6a 100644 (file)
@@ -29,21 +29,12 @@ extern int smp_num_siblings;
 extern unsigned int num_processors;
 extern cpumask_t cpu_initialized;
 
-#ifdef CONFIG_SMP
-extern u16 x86_cpu_to_apicid_init[];
-extern u16 x86_bios_cpu_apicid_init[];
-extern void *x86_cpu_to_apicid_early_ptr;
-extern void *x86_bios_cpu_apicid_early_ptr;
-#else
-#define x86_cpu_to_apicid_early_ptr NULL
-#define x86_bios_cpu_apicid_early_ptr NULL
-#endif
-
 DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
 DECLARE_PER_CPU(cpumask_t, cpu_core_map);
 DECLARE_PER_CPU(u16, cpu_llc_id);
-DECLARE_PER_CPU(u16, x86_cpu_to_apicid);
-DECLARE_PER_CPU(u16, x86_bios_cpu_apicid);
+
+DECLARE_EARLY_PER_CPU(u16, x86_cpu_to_apicid);
+DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
 
 /* Static state in head.S used to set up a CPU */
 extern struct {
@@ -118,8 +109,6 @@ int native_cpu_up(unsigned int cpunum);
 extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
 
-extern void prefill_possible_map(void);
-
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)   per_cpu(x86_cpu_to_apicid, cpu)
 
@@ -130,6 +119,14 @@ static inline int num_booting_cpus(void)
 }
 #endif /* CONFIG_SMP */
 
+#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_CPU)
+extern void prefill_possible_map(void);
+#else
+static inline void prefill_possible_map(void)
+{
+}
+#endif
+
 extern unsigned disabled_cpus __cpuinitdata;
 
 #ifdef CONFIG_X86_32_SMP
@@ -197,11 +194,9 @@ static inline int hard_smp_processor_id(void)
 #endif /* CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_exit_clear(void);
 extern void cpu_uninit(void);
 #endif
 
-extern void smp_alloc_memory(void);
 extern void lock_ipi_call_lock(void);
 extern void unlock_ipi_call_lock(void);
 #endif /* __ASSEMBLY__ */
index f4bba131d0686733a7060f6d4227977fdf6c2588..774c919dc2323cb7ecb85b1350876146414286db 100644 (file)
 #ifndef _ASM_SRAT_H_
 #define _ASM_SRAT_H_
 
-#ifndef CONFIG_ACPI_SRAT
-#error CONFIG_ACPI_SRAT not defined, and srat.h header has been included
-#endif
-
+#ifdef CONFIG_ACPI_NUMA
 extern int get_memcfg_from_srat(void);
-extern unsigned long *get_zholes_size(int);
+#else
+static inline int get_memcfg_from_srat(void)
+{
+       return 0;
+}
+#endif
 
 #endif /* _ASM_SRAT_H_ */
index b49369ad9a6179d0ca3e29eb1b7ddbf9670318a3..193578cd1fd98af422fb5146c110ca03625d26cb 100644 (file)
@@ -29,81 +29,116 @@ extern char *strchr(const char *s, int c);
 #define __HAVE_ARCH_STRLEN
 extern size_t strlen(const char *s);
 
-static __always_inline void * __memcpy(void * to, const void * from, size_t n)
+static __always_inline void *__memcpy(void *to, const void *from, size_t n)
 {
-int d0, d1, d2;
-__asm__ __volatile__(
-       "rep ; movsl\n\t"
-       "movl %4,%%ecx\n\t"
-       "andl $3,%%ecx\n\t"
-       "jz 1f\n\t"
-       "rep ; movsb\n\t"
-       "1:"
-       : "=&c" (d0), "=&D" (d1), "=&S" (d2)
-       : "0" (n/4), "g" (n), "1" ((long) to), "2" ((long) from)
-       : "memory");
-return (to);
+       int d0, d1, d2;
+       asm volatile("rep ; movsl\n\t"
+                    "movl %4,%%ecx\n\t"
+                    "andl $3,%%ecx\n\t"
+                    "jz 1f\n\t"
+                    "rep ; movsb\n\t"
+                    "1:"
+                    : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+                    : "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from)
+                    : "memory");
+       return to;
 }
 
 /*
  * This looks ugly, but the compiler can optimize it totally,
  * as the count is constant.
  */
-static __always_inline void * __constant_memcpy(void * to, const void * from, size_t n)
+static __always_inline void *__constant_memcpy(void *to, const void *from,
+                                              size_t n)
 {
        long esi, edi;
-       if (!n) return to;
-#if 1  /* want to do small copies with non-string ops? */
+       if (!n)
+               return to;
+
        switch (n) {
-               case 1: *(char*)to = *(char*)from; return to;
-               case 2: *(short*)to = *(short*)from; return to;
-               case 4: *(int*)to = *(int*)from; return to;
-#if 1  /* including those doable with two moves? */
-               case 3: *(short*)to = *(short*)from;
-                       *((char*)to+2) = *((char*)from+2); return to;
-               case 5: *(int*)to = *(int*)from;
-                       *((char*)to+4) = *((char*)from+4); return to;
-               case 6: *(int*)to = *(int*)from;
-                       *((short*)to+2) = *((short*)from+2); return to;
-               case 8: *(int*)to = *(int*)from;
-                       *((int*)to+1) = *((int*)from+1); return to;
-#endif
+       case 1:
+               *(char *)to = *(char *)from;
+               return to;
+       case 2:
+               *(short *)to = *(short *)from;
+               return to;
+       case 4:
+               *(int *)to = *(int *)from;
+               return to;
+
+       case 3:
+               *(short *)to = *(short *)from;
+               *((char *)to + 2) = *((char *)from + 2);
+               return to;
+       case 5:
+               *(int *)to = *(int *)from;
+               *((char *)to + 4) = *((char *)from + 4);
+               return to;
+       case 6:
+               *(int *)to = *(int *)from;
+               *((short *)to + 2) = *((short *)from + 2);
+               return to;
+       case 8:
+               *(int *)to = *(int *)from;
+               *((int *)to + 1) = *((int *)from + 1);
+               return to;
        }
-#endif
-       esi = (long) from;
-       edi = (long) to;
-       if (n >= 5*4) {
+
+       esi = (long)from;
+       edi = (long)to;
+       if (n >= 5 * 4) {
                /* large block: use rep prefix */
                int ecx;
-               __asm__ __volatile__(
-                       "rep ; movsl"
-                       : "=&c" (ecx), "=&D" (edi), "=&S" (esi)
-                       : "0" (n/4), "1" (edi),"2" (esi)
-                       : "memory"
+               asm volatile("rep ; movsl"
+                            : "=&c" (ecx), "=&D" (edi), "=&S" (esi)
+                            : "0" (n / 4), "1" (edi), "2" (esi)
+                            : "memory"
                );
        } else {
                /* small block: don't clobber ecx + smaller code */
-               if (n >= 4*4) __asm__ __volatile__("movsl"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
-               if (n >= 3*4) __asm__ __volatile__("movsl"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
-               if (n >= 2*4) __asm__ __volatile__("movsl"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
-               if (n >= 1*4) __asm__ __volatile__("movsl"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
+               if (n >= 4 * 4)
+                       asm volatile("movsl"
+                                    : "=&D"(edi), "=&S"(esi)
+                                    : "0"(edi), "1"(esi)
+                                    : "memory");
+               if (n >= 3 * 4)
+                       asm volatile("movsl"
+                                    : "=&D"(edi), "=&S"(esi)
+                                    : "0"(edi), "1"(esi)
+                                    : "memory");
+               if (n >= 2 * 4)
+                       asm volatile("movsl"
+                                    : "=&D"(edi), "=&S"(esi)
+                                    : "0"(edi), "1"(esi)
+                                    : "memory");
+               if (n >= 1 * 4)
+                       asm volatile("movsl"
+                                    : "=&D"(edi), "=&S"(esi)
+                                    : "0"(edi), "1"(esi)
+                                    : "memory");
        }
        switch (n % 4) {
                /* tail */
-               case 0: return to;
-               case 1: __asm__ __volatile__("movsb"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
-                       return to;
-               case 2: __asm__ __volatile__("movsw"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
-                       return to;
-               default: __asm__ __volatile__("movsw\n\tmovsb"
-                       :"=&D"(edi),"=&S"(esi):"0"(edi),"1"(esi):"memory");
-                       return to;
+       case 0:
+               return to;
+       case 1:
+               asm volatile("movsb"
+                            : "=&D"(edi), "=&S"(esi)
+                            : "0"(edi), "1"(esi)
+                            : "memory");
+               return to;
+       case 2:
+               asm volatile("movsw"
+                            : "=&D"(edi), "=&S"(esi)
+                            : "0"(edi), "1"(esi)
+                            : "memory");
+               return to;
+       default:
+               asm volatile("movsw\n\tmovsb"
+                            : "=&D"(edi), "=&S"(esi)
+                            : "0"(edi), "1"(esi)
+                            : "memory");
+               return to;
        }
 }
 
@@ -117,87 +152,86 @@ static __always_inline void * __constant_memcpy(void * to, const void * from, si
  *     This CPU favours 3DNow strongly (eg AMD Athlon)
  */
 
-static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
+static inline void *__constant_memcpy3d(void *to, const void *from, size_t len)
 {
        if (len < 512)
                return __constant_memcpy(to, from, len);
        return _mmx_memcpy(to, from, len);
 }
 
-static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
+static inline void *__memcpy3d(void *to, const void *from, size_t len)
 {
        if (len < 512)
                return __memcpy(to, from, len);
        return _mmx_memcpy(to, from, len);
 }
 
-#define memcpy(t, f, n) \
-(__builtin_constant_p(n) ? \
__constant_memcpy3d((t),(f),(n)) : \
__memcpy3d((t),(f),(n)))
+#define memcpy(t, f, n)                                \
+       (__builtin_constant_p((n))              \
       ? __constant_memcpy3d((t), (f), (n))   \
       : __memcpy3d((t), (f), (n)))
 
 #else
 
 /*
  *     No 3D Now!
  */
-#define memcpy(t, f, n) \
-(__builtin_constant_p(n) ? \
__constant_memcpy((t),(f),(n)) : \
__memcpy((t),(f),(n)))
+
+#define memcpy(t, f, n)                                \
+       (__builtin_constant_p((n))              \
       ? __constant_memcpy((t), (f), (n))     \
       : __memcpy((t), (f), (n)))
 
 #endif
 
 #define __HAVE_ARCH_MEMMOVE
-void *memmove(void * dest,const void * src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
 
 #define memcmp __builtin_memcmp
 
 #define __HAVE_ARCH_MEMCHR
-extern void *memchr(const void * cs,int c,size_t count);
+extern void *memchr(const void *cs, int c, size_t count);
 
-static inline void * __memset_generic(void * s, char c,size_t count)
+static inline void *__memset_generic(void *s, char c, size_t count)
 {
-int d0, d1;
-__asm__ __volatile__(
-       "rep\n\t"
-       "stosb"
-       : "=&c" (d0), "=&D" (d1)
-       :"a" (c),"1" (s),"0" (count)
-       :"memory");
-return s;
+       int d0, d1;
+       asm volatile("rep\n\t"
+                    "stosb"
+                    : "=&c" (d0), "=&D" (d1)
+                    : "a" (c), "1" (s), "0" (count)
+                    : "memory");
+       return s;
 }
 
 /* we might want to write optimized versions of these later */
-#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
+#define __constant_count_memset(s, c, count) __memset_generic((s), (c), (count))
 
 /*
- * memset(x,0,y) is a reasonably common thing to do, so we want to fill
+ * memset(x, 0, y) is a reasonably common thing to do, so we want to fill
  * things 32 bits at a time even when we don't know the size of the
  * area at compile-time..
  */
-static __always_inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
+static __always_inline
+void *__constant_c_memset(void *s, unsigned long c, size_t count)
 {
-int d0, d1;
-__asm__ __volatile__(
-       "rep ; stosl\n\t"
-       "testb $2,%b3\n\t"
-       "je 1f\n\t"
-       "stosw\n"
-       "1:\ttestb $1,%b3\n\t"
-       "je 2f\n\t"
-       "stosb\n"
-       "2:"
-       :"=&c" (d0), "=&D" (d1)
-       :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
-       :"memory");
-return (s);    
+       int d0, d1;
+       asm volatile("rep ; stosl\n\t"
+                    "testb $2,%b3\n\t"
+                    "je 1f\n\t"
+                    "stosw\n"
+                    "1:\ttestb $1,%b3\n\t"
+                    "je 2f\n\t"
+                    "stosb\n"
+                    "2:"
+                    : "=&c" (d0), "=&D" (d1)
+                    : "a" (c), "q" (count), "0" (count/4), "1" ((long)s)
+                    : "memory");
+       return s;
 }
 
 /* Added by Gertjan van Wingerde to make minix and sysv module work */
 #define __HAVE_ARCH_STRNLEN
-extern size_t strnlen(const char * s, size_t count);
+extern size_t strnlen(const char *s, size_t count);
 /* end of additional stuff */
 
 #define __HAVE_ARCH_STRSTR
@@ -207,66 +241,85 @@ extern char *strstr(const char *cs, const char *ct);
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
  */
-static __always_inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
+static __always_inline
+void *__constant_c_and_count_memset(void *s, unsigned long pattern,
+                                   size_t count)
 {
        switch (count) {
+       case 0:
+               return s;
+       case 1:
+               *(unsigned char *)s = pattern & 0xff;
+               return s;
+       case 2:
+               *(unsigned short *)s = pattern & 0xffff;
+               return s;
+       case 3:
+               *(unsigned short *)s = pattern & 0xffff;
+               *((unsigned char *)s + 2) = pattern & 0xff;
+               return s;
+       case 4:
+               *(unsigned long *)s = pattern;
+               return s;
+       }
+
+#define COMMON(x)                                                      \
+       asm volatile("rep ; stosl"                                      \
+                    x                                                  \
+                    : "=&c" (d0), "=&D" (d1)                           \
+                    : "a" (eax), "0" (count/4), "1" ((long)s)  \
+                    : "memory")
+
+       {
+               int d0, d1;
+#if __GNUC__ == 4 && __GNUC_MINOR__ == 0
+               /* Workaround for broken gcc 4.0 */
+               register unsigned long eax asm("%eax") = pattern;
+#else
+               unsigned long eax = pattern;
+#endif
+
+               switch (count % 4) {
                case 0:
+                       COMMON("");
                        return s;
                case 1:
-                       *(unsigned char *)s = pattern & 0xff;
+                       COMMON("\n\tstosb");
                        return s;
                case 2:
-                       *(unsigned short *)s = pattern & 0xffff;
+                       COMMON("\n\tstosw");
                        return s;
-               case 3:
-                       *(unsigned short *)s = pattern & 0xffff;
-                       *(2+(unsigned char *)s) = pattern & 0xff;
-                       return s;
-               case 4:
-                       *(unsigned long *)s = pattern;
+               default:
+                       COMMON("\n\tstosw\n\tstosb");
                        return s;
+               }
        }
-#define COMMON(x) \
-__asm__  __volatile__( \
-       "rep ; stosl" \
-       x \
-       : "=&c" (d0), "=&D" (d1) \
-       : "a" (pattern),"0" (count/4),"1" ((long) s) \
-       : "memory")
-{
-       int d0, d1;
-       switch (count % 4) {
-               case 0: COMMON(""); return s;
-               case 1: COMMON("\n\tstosb"); return s;
-               case 2: COMMON("\n\tstosw"); return s;
-               default: COMMON("\n\tstosw\n\tstosb"); return s;
-       }
-}
-  
+
 #undef COMMON
 }
 
-#define __constant_c_x_memset(s, c, count) \
-(__builtin_constant_p(count) ? \
__constant_c_and_count_memset((s),(c),(count)) : \
__constant_c_memset((s),(c),(count)))
+#define __constant_c_x_memset(s, c, count)                     \
+       (__builtin_constant_p(count)                            \
       ? __constant_c_and_count_memset((s), (c), (count))     \
       : __constant_c_memset((s), (c), (count)))
 
-#define __memset(s, c, count) \
-(__builtin_constant_p(count) ? \
__constant_count_memset((s),(c),(count)) : \
__memset_generic((s),(c),(count)))
+#define __memset(s, c, count)                          \
+       (__builtin_constant_p(count)                    \
       ? __constant_count_memset((s), (c), (count))   \
       : __memset_generic((s), (c), (count)))
 
 #define __HAVE_ARCH_MEMSET
-#define memset(s, c, count) \
-(__builtin_constant_p(c) ? \
- __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
- __memset((s),(c),(count)))
+#define memset(s, c, count)                                            \
+       (__builtin_constant_p(c)                                        \
+        ? __constant_c_x_memset((s), (0x01010101UL * (unsigned char)(c)), \
+                                (count))                               \
+        : __memset((s), (c), (count)))
 
 /*
  * find the first occurrence of byte 'c', or 1 past the area if none
  */
 #define __HAVE_ARCH_MEMSCAN
-extern void *memscan(void * addr, int c, size_t size);
+extern void *memscan(void *addr, int c, size_t size);
 
 #endif /* __KERNEL__ */
 
index 24e1c080aa8a82c9f434285b1bce48a67c2af54a..8675c6782a7da2754a4b391bab931b920db9a009 100644 (file)
@@ -3,6 +3,9 @@
  * Based on code
  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
  */
+#ifndef __ASM_X86_32_SUSPEND_H
+#define __ASM_X86_32_SUSPEND_H
+
 #include <asm/desc.h>
 #include <asm/i387.h>
 
@@ -44,3 +47,5 @@ static inline void acpi_save_register_state(unsigned long return_point)
 /* routines for saving/restoring kernel state */
 extern int acpi_save_state_mem(void);
 #endif
+
+#endif /* __ASM_X86_32_SUSPEND_H */
index a2f04cd79b29617e4677a0a1a1c23f4f1d434b23..983ce37c491fd83504fd0a82ff3a7da15f608861 100644 (file)
@@ -136,7 +136,7 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" \
 #define set_base(ldt, base) _set_base(((char *)&(ldt)) , (base))
 #define set_limit(ldt, limit) _set_limit(((char *)&(ldt)) , ((limit)-1))
 
-extern void load_gs_index(unsigned);
+extern void native_load_gs_index(unsigned);
 
 /*
  * Load a segment. Fall back on loading the zero
@@ -153,14 +153,14 @@ extern void load_gs_index(unsigned);
                     "jmp 2b\n"                 \
                     ".previous\n"              \
                     _ASM_EXTABLE(1b,3b)        \
-                    : :"r" (value), "r" (0))
+                    : :"r" (value), "r" (0) : "memory")
 
 
 /*
  * Save a segment register away
  */
 #define savesegment(seg, value)                                \
-       asm volatile("mov %%" #seg ",%0":"=rm" (value))
+       asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
 
 static inline unsigned long get_limit(unsigned long segment)
 {
@@ -282,6 +282,7 @@ static inline void native_wbinvd(void)
 #ifdef CONFIG_X86_64
 #define read_cr8()     (native_read_cr8())
 #define write_cr8(x)   (native_write_cr8(x))
+#define load_gs_index   native_load_gs_index
 #endif
 
 /* Clear the 'TS' bit */
@@ -289,7 +290,7 @@ static inline void native_wbinvd(void)
 
 #endif/* CONFIG_PARAVIRT */
 
-#define stts() write_cr0(8 | read_cr0())
+#define stts() write_cr0(read_cr0() | X86_CR0_TS)
 
 #endif /* __KERNEL__ */
 
@@ -303,7 +304,6 @@ static inline void clflush(volatile void *__p)
 void disable_hlt(void);
 void enable_hlt(void);
 
-extern int es7000_plat;
 void cpu_idle_wait(void);
 
 extern unsigned long arch_align_stack(unsigned long sp);
index 77244f17993f303d8e80e8af7b0f71e50e69f0a7..895339d2bc0bae799af368ec10efff5050d5afc3 100644 (file)
@@ -1,9 +1,253 @@
+/* thread_info.h: low-level thread information
+ *
+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ */
+
 #ifndef _ASM_X86_THREAD_INFO_H
+#define _ASM_X86_THREAD_INFO_H
+
+#include <linux/compiler.h>
+#include <asm/page.h>
+#include <asm/types.h>
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ */
+#ifndef __ASSEMBLY__
+struct task_struct;
+struct exec_domain;
+#include <asm/processor.h>
+
+struct thread_info {
+       struct task_struct      *task;          /* main task structure */
+       struct exec_domain      *exec_domain;   /* execution domain */
+       unsigned long           flags;          /* low level flags */
+       __u32                   status;         /* thread synchronous flags */
+       __u32                   cpu;            /* current CPU */
+       int                     preempt_count;  /* 0 => preemptable,
+                                                  <0 => BUG */
+       mm_segment_t            addr_limit;
+       struct restart_block    restart_block;
+       void __user             *sysenter_return;
+#ifdef CONFIG_X86_32
+       unsigned long           previous_esp;   /* ESP of the previous stack in
+                                                  case of nested (IRQ) stacks
+                                               */
+       __u8                    supervisor_stack[0];
+#endif
+};
+
+#define INIT_THREAD_INFO(tsk)                  \
+{                                              \
+       .task           = &tsk,                 \
+       .exec_domain    = &default_exec_domain, \
+       .flags          = 0,                    \
+       .cpu            = 0,                    \
+       .preempt_count  = 1,                    \
+       .addr_limit     = KERNEL_DS,            \
+       .restart_block = {                      \
+               .fn = do_no_restart_syscall,    \
+       },                                      \
+}
+
+#define init_thread_info       (init_thread_union.thread_info)
+#define init_stack             (init_thread_union.stack)
+
+#else /* !__ASSEMBLY__ */
+
+#include <asm/asm-offsets.h>
+
+#endif
+
+/*
+ * thread information flags
+ * - these are process state flags that various assembly files
+ *   may need to access
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ * Warning: layout of LSW is hardcoded in entry.S
+ */
+#define TIF_SYSCALL_TRACE      0       /* syscall trace active */
+#define TIF_SIGPENDING         2       /* signal pending */
+#define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_SINGLESTEP         4       /* reenable singlestep on user return*/
+#define TIF_IRET               5       /* force IRET */
 #ifdef CONFIG_X86_32
-# include "thread_info_32.h"
+#define TIF_SYSCALL_EMU                6       /* syscall emulation active */
+#endif
+#define TIF_SYSCALL_AUDIT      7       /* syscall auditing active */
+#define TIF_SECCOMP            8       /* secure computing */
+#define TIF_MCE_NOTIFY         10      /* notify userspace of an MCE */
+#define TIF_HRTICK_RESCHED     11      /* reprogram hrtick timer */
+#define TIF_NOTSC              16      /* TSC is not accessible in userland */
+#define TIF_IA32               17      /* 32bit process */
+#define TIF_FORK               18      /* ret_from_fork */
+#define TIF_ABI_PENDING                19
+#define TIF_MEMDIE             20
+#define TIF_DEBUG              21      /* uses debug registers */
+#define TIF_IO_BITMAP          22      /* uses I/O bitmap */
+#define TIF_FREEZE             23      /* is freezing for suspend */
+#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_BTS_TRACE_TS       27      /* record scheduling event timestamps */
+
+#define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
+#define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
+#define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
+#define _TIF_IRET              (1 << TIF_IRET)
+#ifdef CONFIG_X86_32
+#define _TIF_SYSCALL_EMU       (1 << TIF_SYSCALL_EMU)
 #else
-# include "thread_info_64.h"
+#define _TIF_SYSCALL_EMU       0
 #endif
+#define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP           (1 << TIF_SECCOMP)
+#define _TIF_MCE_NOTIFY                (1 << TIF_MCE_NOTIFY)
+#define _TIF_HRTICK_RESCHED    (1 << TIF_HRTICK_RESCHED)
+#define _TIF_NOTSC             (1 << TIF_NOTSC)
+#define _TIF_IA32              (1 << TIF_IA32)
+#define _TIF_FORK              (1 << TIF_FORK)
+#define _TIF_ABI_PENDING       (1 << TIF_ABI_PENDING)
+#define _TIF_DEBUG             (1 << TIF_DEBUG)
+#define _TIF_IO_BITMAP         (1 << TIF_IO_BITMAP)
+#define _TIF_FREEZE            (1 << TIF_FREEZE)
+#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_BTS_TRACE_TS      (1 << TIF_BTS_TRACE_TS)
+
+/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK                                                 \
+       (0x0000FFFF &                                                   \
+        ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|       \
+        _TIF_SECCOMP|_TIF_SYSCALL_EMU))
+
+/* work to do on any return to user space */
+#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
+
+/* Only used for 64 bit */
+#define _TIF_DO_NOTIFY_MASK                                            \
+       (_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY|_TIF_HRTICK_RESCHED)
+
+/* flags to check in __switch_to() */
+#define _TIF_WORK_CTXSW                                                        \
+       (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \
+                                                               _TIF_NOTSC)
+
+#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
+#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
+
+#define PREEMPT_ACTIVE         0x10000000
+
+/* thread information allocation */
+#ifdef CONFIG_DEBUG_STACK_USAGE
+#define THREAD_FLAGS (GFP_KERNEL | __GFP_ZERO)
+#else
+#define THREAD_FLAGS GFP_KERNEL
+#endif
+
+#define alloc_thread_info(tsk)                                         \
+       ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
+
+#ifdef CONFIG_X86_32
+
+#define STACK_WARN     (THREAD_SIZE/8)
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+#ifndef __ASSEMBLY__
+
+
+/* how to get the current stack pointer from C */
+register unsigned long current_stack_pointer asm("esp") __used;
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+       return (struct thread_info *)
+               (current_stack_pointer & ~(THREAD_SIZE - 1));
+}
+
+#else /* !__ASSEMBLY__ */
+
+/* how to get the thread information struct from ASM */
+#define GET_THREAD_INFO(reg)    \
+       movl $-THREAD_SIZE, reg; \
+       andl %esp, reg
+
+/* use this one if reg already contains %esp */
+#define GET_THREAD_INFO_WITH_ESP(reg) \
+       andl $-THREAD_SIZE, reg
+
+#endif
+
+#else /* X86_32 */
+
+#include <asm/pda.h>
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+#ifndef __ASSEMBLY__
+static inline struct thread_info *current_thread_info(void)
+{
+       struct thread_info *ti;
+       ti = (void *)(read_pda(kernelstack) + PDA_STACKOFFSET - THREAD_SIZE);
+       return ti;
+}
+
+/* do not use in interrupt context */
+static inline struct thread_info *stack_thread_info(void)
+{
+       struct thread_info *ti;
+       asm("andq %%rsp,%0; " : "=r" (ti) : "0" (~(THREAD_SIZE - 1)));
+       return ti;
+}
+
+#else /* !__ASSEMBLY__ */
+
+/* how to get the thread information struct from ASM */
+#define GET_THREAD_INFO(reg) \
+       movq %gs:pda_kernelstack,reg ; \
+       subq $(THREAD_SIZE-PDA_STACKOFFSET),reg
+
+#endif
+
+#endif /* !X86_32 */
+
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_USEDFPU             0x0001  /* FPU was used by this task
+                                          this quantum (SMP) */
+#define TS_COMPAT              0x0002  /* 32bit syscall active (64BIT)*/
+#define TS_POLLING             0x0004  /* true if in idle loop
+                                          and not sleeping */
+#define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
+
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK       1
+static inline void set_restore_sigmask(void)
+{
+       struct thread_info *ti = current_thread_info();
+       ti->status |= TS_RESTORE_SIGMASK;
+       set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
 
 #ifndef __ASSEMBLY__
 extern void arch_task_cache_init(void);
diff --git a/include/asm-x86/thread_info_32.h b/include/asm-x86/thread_info_32.h
deleted file mode 100644 (file)
index b633882..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/* thread_info.h: i386 low-level thread information
- *
- * Copyright (C) 2002  David Howells (dhowells@redhat.com)
- * - Incorporating suggestions made by Linus Torvalds and Dave Miller
- */
-
-#ifndef _ASM_THREAD_INFO_H
-#define _ASM_THREAD_INFO_H
-
-#ifdef __KERNEL__
-
-#include <linux/compiler.h>
-#include <asm/page.h>
-
-#ifndef __ASSEMBLY__
-#include <asm/processor.h>
-#endif
-
-/*
- * low level task data that entry.S needs immediate access to
- * - this struct should fit entirely inside of one cache line
- * - this struct shares the supervisor stack pages
- * - if the contents of this structure are changed,
- *   the assembly constants must also be changed
- */
-#ifndef __ASSEMBLY__
-
-struct thread_info {
-       struct task_struct      *task;          /* main task structure */
-       struct exec_domain      *exec_domain;   /* execution domain */
-       unsigned long           flags;          /* low level flags */
-       unsigned long           status;         /* thread-synchronous flags */
-       __u32                   cpu;            /* current CPU */
-       int                     preempt_count;  /* 0 => preemptable,
-                                                  <0 => BUG */
-       mm_segment_t            addr_limit;     /* thread address space:
-                                                  0-0xBFFFFFFF user-thread
-                                                  0-0xFFFFFFFF kernel-thread
-                                               */
-       void                    *sysenter_return;
-       struct restart_block    restart_block;
-       unsigned long           previous_esp;   /* ESP of the previous stack in
-                                                  case of nested (IRQ) stacks
-                                               */
-       __u8                    supervisor_stack[0];
-};
-
-#else /* !__ASSEMBLY__ */
-
-#include <asm/asm-offsets.h>
-
-#endif
-
-#define PREEMPT_ACTIVE         0x10000000
-#ifdef CONFIG_4KSTACKS
-#define THREAD_SIZE            (4096)
-#else
-#define THREAD_SIZE            (8192)
-#endif
-
-#define STACK_WARN             (THREAD_SIZE/8)
-/*
- * macros/functions for gaining access to the thread information structure
- *
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-#ifndef __ASSEMBLY__
-
-#define INIT_THREAD_INFO(tsk)                  \
-{                                              \
-       .task           = &tsk,                 \
-       .exec_domain    = &default_exec_domain, \
-       .flags          = 0,                    \
-       .cpu            = 0,                    \
-       .preempt_count  = 1,                    \
-       .addr_limit     = KERNEL_DS,            \
-       .restart_block = {                      \
-               .fn = do_no_restart_syscall,    \
-       },                                      \
-}
-
-#define init_thread_info       (init_thread_union.thread_info)
-#define init_stack             (init_thread_union.stack)
-
-
-/* how to get the current stack pointer from C */
-register unsigned long current_stack_pointer asm("esp") __used;
-
-/* how to get the thread information struct from C */
-static inline struct thread_info *current_thread_info(void)
-{
-       return (struct thread_info *)
-               (current_stack_pointer & ~(THREAD_SIZE - 1));
-}
-
-/* thread information allocation */
-#ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk) ((struct thread_info *)                 \
-       __get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(THREAD_SIZE)))
-#else
-#define alloc_thread_info(tsk) ((struct thread_info *)                 \
-       __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)))
-#endif
-
-#else /* !__ASSEMBLY__ */
-
-/* how to get the thread information struct from ASM */
-#define GET_THREAD_INFO(reg)    \
-       movl $-THREAD_SIZE, reg; \
-       andl %esp, reg
-
-/* use this one if reg already contains %esp */
-#define GET_THREAD_INFO_WITH_ESP(reg) \
-       andl $-THREAD_SIZE, reg
-
-#endif
-
-/*
- * thread information flags
- * - these are process state flags that various
- *   assembly files may need to access
- * - pending work-to-be-done flags are in LSW
- * - 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_SYSCALL_EMU                5       /* syscall emulation active */
-#define TIF_SYSCALL_AUDIT      6       /* syscall auditing active */
-#define TIF_SECCOMP            7       /* secure computing */
-#define TIF_HRTICK_RESCHED     9       /* reprogram hrtick timer */
-#define TIF_MEMDIE             16
-#define TIF_DEBUG              17      /* uses debug registers */
-#define TIF_IO_BITMAP          18      /* uses I/O bitmap */
-#define TIF_FREEZE             19      /* is freezing for suspend */
-#define TIF_NOTSC              20      /* TSC is not accessible in userland */
-#define TIF_FORCED_TF          21      /* true if TF in eflags artificially */
-#define TIF_DEBUGCTLMSR                22      /* uses thread_struct.debugctlmsr */
-#define TIF_DS_AREA_MSR        23      /* uses thread_struct.ds_area_msr */
-#define TIF_BTS_TRACE_TS        24      /* record scheduling event timestamps */
-
-#define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
-#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_SYSCALL_EMU       (1 << TIF_SYSCALL_EMU)
-#define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SECCOMP           (1 << TIF_SECCOMP)
-#define _TIF_HRTICK_RESCHED    (1 << TIF_HRTICK_RESCHED)
-#define _TIF_DEBUG             (1 << TIF_DEBUG)
-#define _TIF_IO_BITMAP         (1 << TIF_IO_BITMAP)
-#define _TIF_FREEZE            (1 << TIF_FREEZE)
-#define _TIF_NOTSC             (1 << TIF_NOTSC)
-#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_BTS_TRACE_TS      (1 << TIF_BTS_TRACE_TS)
-
-/* work to do on interrupt/exception return */
-#define _TIF_WORK_MASK                                                 \
-       (0x0000FFFF & ~(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT |       \
-                       _TIF_SECCOMP | _TIF_SYSCALL_EMU))
-/* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK      (0x0000FFFF & ~_TIF_SECCOMP)
-
-/* flags to check in __switch_to() */
-#define _TIF_WORK_CTXSW                                                \
-       (_TIF_IO_BITMAP | _TIF_NOTSC | _TIF_DEBUGCTLMSR |       \
-        _TIF_DS_AREA_MSR | _TIF_BTS_TRACE_TS)
-#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
-#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW | _TIF_DEBUG)
-
-
-/*
- * Thread-synchronous status.
- *
- * This is different from the flags in that nobody else
- * ever touches our thread-synchronous status, so we don't
- * have to worry about atomic accesses.
- */
-#define TS_USEDFPU             0x0001  /* FPU was used by this task
-                                          this quantum (SMP) */
-#define TS_POLLING             0x0002  /* True if in idle loop
-                                          and not sleeping */
-#define TS_RESTORE_SIGMASK     0x0004  /* restore signal mask in do_signal() */
-
-#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
-
-#ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       set_bit(TIF_SIGPENDING, &ti->flags);
-}
-#endif /* !__ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h
deleted file mode 100644 (file)
index cb69f70..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/* thread_info.h: x86_64 low-level thread information
- *
- * Copyright (C) 2002  David Howells (dhowells@redhat.com)
- * - Incorporating suggestions made by Linus Torvalds and Dave Miller
- */
-
-#ifndef _ASM_THREAD_INFO_H
-#define _ASM_THREAD_INFO_H
-
-#ifdef __KERNEL__
-
-#include <asm/page.h>
-#include <asm/types.h>
-#include <asm/pda.h>
-
-/*
- * low level task data that entry.S needs immediate access to
- * - this struct should fit entirely inside of one cache line
- * - this struct shares the supervisor stack pages
- */
-#ifndef __ASSEMBLY__
-struct task_struct;
-struct exec_domain;
-#include <asm/processor.h>
-
-struct thread_info {
-       struct task_struct      *task;          /* main task structure */
-       struct exec_domain      *exec_domain;   /* execution domain */
-       __u32                   flags;          /* low level flags */
-       __u32                   status;         /* thread synchronous flags */
-       __u32                   cpu;            /* current CPU */
-       int                     preempt_count;  /* 0 => preemptable,
-                                                  <0 => BUG */
-       mm_segment_t            addr_limit;
-       struct restart_block    restart_block;
-#ifdef CONFIG_IA32_EMULATION
-       void __user             *sysenter_return;
-#endif
-};
-#endif
-
-/*
- * macros/functions for gaining access to the thread information structure
- * preempt_count needs to be 1 initially, until the scheduler is functional.
- */
-#ifndef __ASSEMBLY__
-#define INIT_THREAD_INFO(tsk)                  \
-{                                              \
-       .task          = &tsk,                  \
-       .exec_domain   = &default_exec_domain,  \
-       .flags         = 0,                     \
-       .cpu           = 0,                     \
-       .preempt_count = 1,                     \
-       .addr_limit     = KERNEL_DS,            \
-       .restart_block = {                      \
-               .fn = do_no_restart_syscall,    \
-       },                                      \
-}
-
-#define init_thread_info       (init_thread_union.thread_info)
-#define init_stack             (init_thread_union.stack)
-
-static inline struct thread_info *current_thread_info(void)
-{
-       struct thread_info *ti;
-       ti = (void *)(read_pda(kernelstack) + PDA_STACKOFFSET - THREAD_SIZE);
-       return ti;
-}
-
-/* do not use in interrupt context */
-static inline struct thread_info *stack_thread_info(void)
-{
-       struct thread_info *ti;
-       asm("andq %%rsp,%0; " : "=r" (ti) : "0" (~(THREAD_SIZE - 1)));
-       return ti;
-}
-
-/* thread information allocation */
-#ifdef CONFIG_DEBUG_STACK_USAGE
-#define THREAD_FLAGS (GFP_KERNEL | __GFP_ZERO)
-#else
-#define THREAD_FLAGS GFP_KERNEL
-#endif
-
-#define alloc_thread_info(tsk)                                         \
-       ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
-
-#else /* !__ASSEMBLY__ */
-
-/* how to get the thread information struct from ASM */
-#define GET_THREAD_INFO(reg) \
-       movq %gs:pda_kernelstack,reg ; \
-       subq $(THREAD_SIZE-PDA_STACKOFFSET),reg
-
-#endif
-
-/*
- * thread information flags
- * - these are process state flags that various assembly files
- *   may need to access
- * - pending work-to-be-done flags are in LSW
- * - other flags in MSW
- * Warning: layout of LSW is hardcoded in entry.S
- */
-#define TIF_SYSCALL_TRACE      0       /* syscall trace active */
-#define TIF_SIGPENDING         2       /* signal pending */
-#define TIF_NEED_RESCHED       3       /* rescheduling necessary */
-#define TIF_SINGLESTEP         4       /* reenable singlestep on user return*/
-#define TIF_IRET               5       /* force IRET */
-#define TIF_SYSCALL_AUDIT      7       /* syscall auditing active */
-#define TIF_SECCOMP            8       /* secure computing */
-#define TIF_MCE_NOTIFY         10      /* notify userspace of an MCE */
-#define TIF_HRTICK_RESCHED     11      /* reprogram hrtick timer */
-/* 16 free */
-#define TIF_IA32               17      /* 32bit process */
-#define TIF_FORK               18      /* ret_from_fork */
-#define TIF_ABI_PENDING                19
-#define TIF_MEMDIE             20
-#define TIF_DEBUG              21      /* uses debug registers */
-#define TIF_IO_BITMAP          22      /* uses I/O bitmap */
-#define TIF_FREEZE             23      /* is freezing for suspend */
-#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_BTS_TRACE_TS       27      /* record scheduling event timestamps */
-#define TIF_NOTSC              28      /* TSC is not accessible in userland */
-
-#define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
-#define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
-#define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
-#define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
-#define _TIF_IRET              (1 << TIF_IRET)
-#define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SECCOMP           (1 << TIF_SECCOMP)
-#define _TIF_MCE_NOTIFY                (1 << TIF_MCE_NOTIFY)
-#define _TIF_HRTICK_RESCHED    (1 << TIF_HRTICK_RESCHED)
-#define _TIF_IA32              (1 << TIF_IA32)
-#define _TIF_FORK              (1 << TIF_FORK)
-#define _TIF_ABI_PENDING       (1 << TIF_ABI_PENDING)
-#define _TIF_DEBUG             (1 << TIF_DEBUG)
-#define _TIF_IO_BITMAP         (1 << TIF_IO_BITMAP)
-#define _TIF_FREEZE            (1 << TIF_FREEZE)
-#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_BTS_TRACE_TS      (1 << TIF_BTS_TRACE_TS)
-#define _TIF_NOTSC             (1 << TIF_NOTSC)
-
-/* work to do on interrupt/exception return */
-#define _TIF_WORK_MASK                                                 \
-       (0x0000FFFF &                                                   \
-        ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
-/* work to do on any return to user space */
-#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
-
-#define _TIF_DO_NOTIFY_MASK                                            \
-       (_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY|_TIF_HRTICK_RESCHED)
-
-/* flags to check in __switch_to() */
-#define _TIF_WORK_CTXSW                                                        \
-       (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS|_TIF_NOTSC)
-#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
-#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
-
-#define PREEMPT_ACTIVE     0x10000000
-
-/*
- * Thread-synchronous status.
- *
- * This is different from the flags in that nobody else
- * ever touches our thread-synchronous status, so we don't
- * have to worry about atomic accesses.
- */
-#define TS_USEDFPU             0x0001  /* FPU was used by this task
-                                          this quantum (SMP) */
-#define TS_COMPAT              0x0002  /* 32bit syscall active */
-#define TS_POLLING             0x0004  /* true if in idle loop
-                                          and not sleeping */
-#define TS_RESTORE_SIGMASK     0x0008  /* restore signal mask in do_signal() */
-
-#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
-
-#ifndef __ASSEMBLY__
-#define HAVE_SET_RESTORE_SIGMASK       1
-static inline void set_restore_sigmask(void)
-{
-       struct thread_info *ti = current_thread_info();
-       ti->status |= TS_RESTORE_SIGMASK;
-       set_bit(TIF_SIGPENDING, &ti->flags);
-}
-#endif /* !__ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_THREAD_INFO_H */
index bce72d7a958c21829aa79c041b4ac2fb06178421..a17fa473e91d41b496972aef624d3ab6483f9f91 100644 (file)
@@ -56,4 +56,6 @@ static inline int native_set_wallclock(unsigned long nowtime)
 
 #endif /* CONFIG_PARAVIRT */
 
+extern unsigned long __init calibrate_cpu(void);
+
 #endif
index 4f6fcb050c11577d4c0640f26513674c1669f4d2..fb2a4ddddf3d083296d0248c759071f3cc450b3e 100644 (file)
@@ -7,14 +7,14 @@
 #define TICK_SIZE (tick_nsec / 1000)
 
 unsigned long long native_sched_clock(void);
-unsigned long native_calculate_cpu_khz(void);
+unsigned long native_calibrate_tsc(void);
 
 extern int timer_ack;
 extern int no_timer_check;
 extern int recalibrate_cpu_khz(void);
 
 #ifndef CONFIG_PARAVIRT
-#define calculate_cpu_khz() native_calculate_cpu_khz()
+#define calibrate_tsc() native_calibrate_tsc()
 #endif
 
 /* Accelerators for sched_clock()
index dcf3f8131d6b4b728643b84cd9d395b0ea4dd963..90ac7718469a5b416bfd90350b24ade716698925 100644 (file)
 # endif
 #endif
 
+/* Node not present */
+#define NUMA_NO_NODE   (-1)
+
 #ifdef CONFIG_NUMA
 #include <linux/cpumask.h>
 #include <asm/mpspec.h>
 
-/* Mappings between logical cpu number and node number */
 #ifdef CONFIG_X86_32
-extern int cpu_to_node_map[];
-#else
-/* Returns the number of the current Node. */
-#define numa_node_id()         (early_cpu_to_node(raw_smp_processor_id()))
-#endif
-
-DECLARE_PER_CPU(int, x86_cpu_to_node_map);
-
-#ifdef CONFIG_SMP
-extern int x86_cpu_to_node_map_init[];
-extern void *x86_cpu_to_node_map_early_ptr;
-#else
-#define x86_cpu_to_node_map_early_ptr NULL
-#endif
 
+/* Mappings between node number and cpus on that node. */
 extern cpumask_t node_to_cpumask_map[];
 
-#define NUMA_NO_NODE   (-1)
+/* Mappings between logical cpu number and node number */
+extern int cpu_to_node_map[];
 
 /* Returns the number of the node containing CPU 'cpu' */
-#ifdef CONFIG_X86_32
-#define early_cpu_to_node(cpu) cpu_to_node(cpu)
 static inline int cpu_to_node(int cpu)
 {
        return cpu_to_node_map[cpu];
 }
+#define early_cpu_to_node(cpu) cpu_to_node(cpu)
 
-#else /* CONFIG_X86_64 */
-
-#ifdef CONFIG_SMP
-static inline int early_cpu_to_node(int cpu)
+/* Returns a bitmask of CPUs on Node 'node'.
+ *
+ * Side note: this function creates the returned cpumask on the stack
+ * so with a high NR_CPUS count, excessive stack space is used.  The
+ * node_to_cpumask_ptr function should be used whenever possible.
+ */
+static inline cpumask_t node_to_cpumask(int node)
 {
-       int *cpu_to_node_map = x86_cpu_to_node_map_early_ptr;
-
-       if (cpu_to_node_map)
-               return cpu_to_node_map[cpu];
-       else if (per_cpu_offset(cpu))
-               return per_cpu(x86_cpu_to_node_map, cpu);
-       else
-               return NUMA_NO_NODE;
+       return node_to_cpumask_map[node];
 }
-#else
-#define        early_cpu_to_node(cpu)  cpu_to_node(cpu)
-#endif
 
+#else /* CONFIG_X86_64 */
+
+/* Mappings between node number and cpus on that node. */
+extern cpumask_t *node_to_cpumask_map;
+
+/* Mappings between logical cpu number and node number */
+DECLARE_EARLY_PER_CPU(int, x86_cpu_to_node_map);
+
+/* Returns the number of the current Node. */
+#define numa_node_id()         read_pda(nodenumber)
+
+#ifdef CONFIG_DEBUG_PER_CPU_MAPS
+extern int cpu_to_node(int cpu);
+extern int early_cpu_to_node(int cpu);
+extern const cpumask_t *_node_to_cpumask_ptr(int node);
+extern cpumask_t node_to_cpumask(int node);
+
+#else  /* !CONFIG_DEBUG_PER_CPU_MAPS */
+
+/* Returns the number of the node containing CPU 'cpu' */
 static inline int cpu_to_node(int cpu)
 {
-#ifdef CONFIG_DEBUG_PER_CPU_MAPS
-       if (x86_cpu_to_node_map_early_ptr) {
-               printk("KERN_NOTICE cpu_to_node(%d): usage too early!\n",
-                      (int)cpu);
-               dump_stack();
-               return ((int *)x86_cpu_to_node_map_early_ptr)[cpu];
-       }
-#endif
        return per_cpu(x86_cpu_to_node_map, cpu);
 }
 
-#ifdef CONFIG_NUMA
+/* Same function but used if called before per_cpu areas are setup */
+static inline int early_cpu_to_node(int cpu)
+{
+       if (early_per_cpu_ptr(x86_cpu_to_node_map))
+               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
+
+       return per_cpu(x86_cpu_to_node_map, cpu);
+}
 
 /* Returns a pointer to the cpumask of CPUs on Node 'node'. */
+static inline const cpumask_t *_node_to_cpumask_ptr(int node)
+{
+       return &node_to_cpumask_map[node];
+}
+
+/* Returns a bitmask of CPUs on Node 'node'. */
+static inline cpumask_t node_to_cpumask(int node)
+{
+       return node_to_cpumask_map[node];
+}
+
+#endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
+
+/* Replace default node_to_cpumask_ptr with optimized version */
 #define node_to_cpumask_ptr(v, node)           \
-               cpumask_t *v = &(node_to_cpumask_map[node])
+               const cpumask_t *v = _node_to_cpumask_ptr(node)
 
 #define node_to_cpumask_ptr_next(v, node)      \
-                          v = &(node_to_cpumask_map[node])
-#endif
+                          v = _node_to_cpumask_ptr(node)
 
 #endif /* CONFIG_X86_64 */
 
@@ -117,20 +131,6 @@ static inline int cpu_to_node(int cpu)
  */
 #define parent_node(node) (node)
 
-/* Returns a bitmask of CPUs on Node 'node'. */
-static inline cpumask_t node_to_cpumask(int node)
-{
-       return node_to_cpumask_map[node];
-}
-
-/* Returns the number of the first CPU on Node 'node'. */
-static inline int node_to_first_cpu(int node)
-{
-       cpumask_t mask = node_to_cpumask(node);
-
-       return first_cpu(mask);
-}
-
 #define pcibus_to_node(bus) __pcibus_to_node(bus)
 #define pcibus_to_cpumask(bus) __pcibus_to_cpumask(bus)
 
@@ -180,12 +180,44 @@ extern int __node_distance(int, int);
 #define node_distance(a, b) __node_distance(a, b)
 #endif
 
-#else /* CONFIG_NUMA */
+#else /* !CONFIG_NUMA */
 
+#define numa_node_id()         0
+#define        cpu_to_node(cpu)        0
+#define        early_cpu_to_node(cpu)  0
+
+static inline const cpumask_t *_node_to_cpumask_ptr(int node)
+{
+       return &cpu_online_map;
+}
+static inline cpumask_t node_to_cpumask(int node)
+{
+       return cpu_online_map;
+}
+static inline int node_to_first_cpu(int node)
+{
+       return first_cpu(cpu_online_map);
+}
+
+/* Replace default node_to_cpumask_ptr with optimized version */
+#define node_to_cpumask_ptr(v, node)           \
+               const cpumask_t *v = _node_to_cpumask_ptr(node)
+
+#define node_to_cpumask_ptr_next(v, node)      \
+                          v = _node_to_cpumask_ptr(node)
 #endif
 
 #include <asm-generic/topology.h>
 
+#ifdef CONFIG_NUMA
+/* Returns the number of the first CPU on Node 'node'. */
+static inline int node_to_first_cpu(int node)
+{
+       node_to_cpumask_ptr(mask, node);
+       return first_cpu(*mask);
+}
+#endif
+
 extern cpumask_t cpu_coregroup_map(int cpu);
 
 #ifdef ENABLE_TOPO_DEFINES
@@ -193,6 +225,9 @@ extern cpumask_t cpu_coregroup_map(int cpu);
 #define topology_core_id(cpu)                  (cpu_data(cpu).cpu_core_id)
 #define topology_core_siblings(cpu)            (per_cpu(cpu_core_map, cpu))
 #define topology_thread_siblings(cpu)          (per_cpu(cpu_sibling_map, cpu))
+
+/* indicates that pointers to the topology cpumask_t maps are valid */
+#define arch_provides_topology_pointers                yes
 #endif
 
 static inline void arch_fix_phys_package_id(int num, u32 slot)
@@ -220,4 +255,4 @@ static inline void set_mp_bus_to_node(int busnum, int node)
 }
 #endif
 
-#endif
+#endif /* _ASM_X86_TOPOLOGY_H */
index 548873ab5fc1b0deabafc4b3dcbb23ee8cbf05db..cb6f6ee45b8f858921ad4cfbcaf1f3f0d6f886a2 100644 (file)
@@ -48,7 +48,6 @@ static __always_inline cycles_t vget_cycles(void)
 extern void tsc_init(void);
 extern void mark_tsc_unstable(char *reason);
 extern int unsynchronized_tsc(void);
-extern void init_tsc_clocksource(void);
 int check_tsc_unstable(void);
 
 /*
@@ -58,7 +57,6 @@ int check_tsc_unstable(void);
 extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
 
-extern void tsc_calibrate(void);
 extern int notsc_setup(char *);
 
 #endif
index 9fefd2947e78581f9310a102752e4e314e0f0dd9..f6fa4d841bbcd3cbd552bb205c84facc688bf050 100644 (file)
@@ -1,5 +1,453 @@
+#ifndef _ASM_UACCES_H_
+#define _ASM_UACCES_H_
+/*
+ * User space memory access functions
+ */
+#include <linux/errno.h>
+#include <linux/compiler.h>
+#include <linux/thread_info.h>
+#include <linux/prefetch.h>
+#include <linux/string.h>
+#include <asm/asm.h>
+#include <asm/page.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+
+#define KERNEL_DS      MAKE_MM_SEG(-1UL)
+#define USER_DS                MAKE_MM_SEG(PAGE_OFFSET)
+
+#define get_ds()       (KERNEL_DS)
+#define get_fs()       (current_thread_info()->addr_limit)
+#define set_fs(x)      (current_thread_info()->addr_limit = (x))
+
+#define segment_eq(a, b)       ((a).seg == (b).seg)
+
+#define __addr_ok(addr)                                        \
+       ((unsigned long __force)(addr) <                \
+        (current_thread_info()->addr_limit.seg))
+
+/*
+ * Test whether a block of memory is a valid user space address.
+ * Returns 0 if the range is valid, nonzero otherwise.
+ *
+ * This is equivalent to the following test:
+ * (u33)addr + (u33)size >= (u33)current->addr_limit.seg (u65 for x86_64)
+ *
+ * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry...
+ */
+
+#define __range_not_ok(addr, size)                                     \
+({                                                                     \
+       unsigned long flag, roksum;                                     \
+       __chk_user_ptr(addr);                                           \
+       asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0"             \
+           : "=&r" (flag), "=r" (roksum)                               \
+           : "1" (addr), "g" ((long)(size)),                           \
+             "rm" (current_thread_info()->addr_limit.seg));            \
+       flag;                                                           \
+})
+
+/**
+ * access_ok: - Checks if a user space pointer is valid
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
+ *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
+ *        to write to a block, it is always safe to read from it.
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
+#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry {
+       unsigned long insn, fixup;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ *
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the ugliness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ */
+
+extern int __get_user_1(void);
+extern int __get_user_2(void);
+extern int __get_user_4(void);
+extern int __get_user_8(void);
+extern int __get_user_bad(void);
+
+#define __get_user_x(size, ret, x, ptr)                      \
+       asm volatile("call __get_user_" #size         \
+                    : "=a" (ret),"=d" (x)            \
+                    : "0" (ptr))                     \
+
+/* Careful: we have to cast the result to the type of the pointer
+ * for sign reasons */
+
+/**
+ * get_user: - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#ifdef CONFIG_X86_32
+#define __get_user_8(__ret_gu, __val_gu, ptr)                          \
+               __get_user_x(X, __ret_gu, __val_gu, ptr)
+#else
+#define __get_user_8(__ret_gu, __val_gu, ptr)                          \
+               __get_user_x(8, __ret_gu, __val_gu, ptr)
+#endif
+
+#define get_user(x, ptr)                                               \
+({                                                                     \
+       int __ret_gu;                                                   \
+       unsigned long __val_gu;                                         \
+       __chk_user_ptr(ptr);                                            \
+       switch (sizeof(*(ptr))) {                                       \
+       case 1:                                                         \
+               __get_user_x(1, __ret_gu, __val_gu, ptr);               \
+               break;                                                  \
+       case 2:                                                         \
+               __get_user_x(2, __ret_gu, __val_gu, ptr);               \
+               break;                                                  \
+       case 4:                                                         \
+               __get_user_x(4, __ret_gu, __val_gu, ptr);               \
+               break;                                                  \
+       case 8:                                                         \
+               __get_user_8(__ret_gu, __val_gu, ptr);                  \
+               break;                                                  \
+       default:                                                        \
+               __get_user_x(X, __ret_gu, __val_gu, ptr);               \
+               break;                                                  \
+       }                                                               \
+       (x) = (__typeof__(*(ptr)))__val_gu;                             \
+       __ret_gu;                                                       \
+})
+
+#define __put_user_x(size, x, ptr, __ret_pu)                   \
+       asm volatile("call __put_user_" #size : "=a" (__ret_pu) \
+                    :"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
+
+
+
+#ifdef CONFIG_X86_32
+#define __put_user_u64(x, addr, err)                                   \
+       asm volatile("1:        movl %%eax,0(%2)\n"                     \
+                    "2:        movl %%edx,4(%2)\n"                     \
+                    "3:\n"                                             \
+                    ".section .fixup,\"ax\"\n"                         \
+                    "4:        movl %3,%0\n"                           \
+                    "  jmp 3b\n"                                       \
+                    ".previous\n"                                      \
+                    _ASM_EXTABLE(1b, 4b)                               \
+                    _ASM_EXTABLE(2b, 4b)                               \
+                    : "=r" (err)                                       \
+                    : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err))
+
+#define __put_user_x8(x, ptr, __ret_pu)                                \
+       asm volatile("call __put_user_8" : "=a" (__ret_pu)      \
+                    : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
+#else
+#define __put_user_u64(x, ptr, retval) \
+       __put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT)
+#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
+#endif
+
+extern void __put_user_bad(void);
+
+/*
+ * Strange magic calling convention: pointer in %ecx,
+ * value in %eax(:%edx), return value in %eax. clobbers %rbx
+ */
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
+extern void __put_user_8(void);
+
+#ifdef CONFIG_X86_WP_WORKS_OK
+
+/**
+ * put_user: - Write a simple value into user space.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define put_user(x, ptr)                                       \
+({                                                             \
+       int __ret_pu;                                           \
+       __typeof__(*(ptr)) __pu_val;                            \
+       __chk_user_ptr(ptr);                                    \
+       __pu_val = x;                                           \
+       switch (sizeof(*(ptr))) {                               \
+       case 1:                                                 \
+               __put_user_x(1, __pu_val, ptr, __ret_pu);       \
+               break;                                          \
+       case 2:                                                 \
+               __put_user_x(2, __pu_val, ptr, __ret_pu);       \
+               break;                                          \
+       case 4:                                                 \
+               __put_user_x(4, __pu_val, ptr, __ret_pu);       \
+               break;                                          \
+       case 8:                                                 \
+               __put_user_x8(__pu_val, ptr, __ret_pu);         \
+               break;                                          \
+       default:                                                \
+               __put_user_x(X, __pu_val, ptr, __ret_pu);       \
+               break;                                          \
+       }                                                       \
+       __ret_pu;                                               \
+})
+
+#define __put_user_size(x, ptr, size, retval, errret)                  \
+do {                                                                   \
+       retval = 0;                                                     \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+       case 1:                                                         \
+               __put_user_asm(x, ptr, retval, "b", "b", "iq", errret); \
+               break;                                                  \
+       case 2:                                                         \
+               __put_user_asm(x, ptr, retval, "w", "w", "ir", errret); \
+               break;                                                  \
+       case 4:                                                         \
+               __put_user_asm(x, ptr, retval, "l", "k",  "ir", errret);\
+               break;                                                  \
+       case 8:                                                         \
+               __put_user_u64((__typeof__(*ptr))(x), ptr, retval);     \
+               break;                                                  \
+       default:                                                        \
+               __put_user_bad();                                       \
+       }                                                               \
+} while (0)
+
+#else
+
+#define __put_user_size(x, ptr, size, retval, errret)                  \
+do {                                                                   \
+       __typeof__(*(ptr))__pus_tmp = x;                                \
+       retval = 0;                                                     \
+                                                                       \
+       if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0))    \
+               retval = errret;                                        \
+} while (0)
+
+#define put_user(x, ptr)                                       \
+({                                                             \
+       int __ret_pu;                                           \
+       __typeof__(*(ptr))__pus_tmp = x;                        \
+       __ret_pu = 0;                                           \
+       if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp,         \
+                                      sizeof(*(ptr))) != 0))   \
+               __ret_pu = -EFAULT;                             \
+       __ret_pu;                                               \
+})
+#endif
+
+#ifdef CONFIG_X86_32
+#define __get_user_asm_u64(x, ptr, retval, errret)     (x) = __get_user_bad()
+#else
+#define __get_user_asm_u64(x, ptr, retval, errret) \
+        __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
+#endif
+
+#define __get_user_size(x, ptr, size, retval, errret)                  \
+do {                                                                   \
+       retval = 0;                                                     \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+       case 1:                                                         \
+               __get_user_asm(x, ptr, retval, "b", "b", "=q", errret); \
+               break;                                                  \
+       case 2:                                                         \
+               __get_user_asm(x, ptr, retval, "w", "w", "=r", errret); \
+               break;                                                  \
+       case 4:                                                         \
+               __get_user_asm(x, ptr, retval, "l", "k", "=r", errret); \
+               break;                                                  \
+       case 8:                                                         \
+               __get_user_asm_u64(x, ptr, retval, errret);             \
+               break;                                                  \
+       default:                                                        \
+               (x) = __get_user_bad();                                 \
+       }                                                               \
+} while (0)
+
+#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
+       asm volatile("1:        mov"itype" %2,%"rtype"1\n"              \
+                    "2:\n"                                             \
+                    ".section .fixup,\"ax\"\n"                         \
+                    "3:        mov %3,%0\n"                            \
+                    "  xor"itype" %"rtype"1,%"rtype"1\n"               \
+                    "  jmp 2b\n"                                       \
+                    ".previous\n"                                      \
+                    _ASM_EXTABLE(1b, 3b)                               \
+                    : "=r" (err), ltype(x)                             \
+                    : "m" (__m(addr)), "i" (errret), "0" (err))
+
+#define __put_user_nocheck(x, ptr, size)                       \
+({                                                             \
+       long __pu_err;                                          \
+       __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \
+       __pu_err;                                               \
+})
+
+#define __get_user_nocheck(x, ptr, size)                               \
+({                                                                     \
+       long __gu_err;                                                  \
+       unsigned long __gu_val;                                         \
+       __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);    \
+       (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
+       __gu_err;                                                       \
+})
+
+/* FIXME: this hack is definitely wrong -AK */
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct __user *)(x))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
+       asm volatile("1:        mov"itype" %"rtype"1,%2\n"              \
+                    "2:\n"                                             \
+                    ".section .fixup,\"ax\"\n"                         \
+                    "3:        mov %3,%0\n"                            \
+                    "  jmp 2b\n"                                       \
+                    ".previous\n"                                      \
+                    _ASM_EXTABLE(1b, 3b)                               \
+                    : "=r"(err)                                        \
+                    : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+
+#define __get_user(x, ptr)                                             \
+       __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+
+#define __put_user(x, ptr)                                             \
+       __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
+#define __get_user_unaligned __get_user
+#define __put_user_unaligned __put_user
+
+/*
+ * movsl can be slow when source and dest are not both 8-byte aligned
+ */
+#ifdef CONFIG_X86_INTEL_USERCOPY
+extern struct movsl_mask {
+       int mask;
+} ____cacheline_aligned_in_smp movsl_mask;
+#endif
+
+#define ARCH_HAS_NOCACHE_UACCESS 1
+
 #ifdef CONFIG_X86_32
 # include "uaccess_32.h"
 #else
+# define ARCH_HAS_SEARCH_EXTABLE
 # include "uaccess_64.h"
 #endif
+
+#endif
index 8e7595c1f34e69959e42eb98a33b2a64b56ba848..6fdef39a0bcb849d86e3bb0e1ade448694d21cdb 100644 (file)
 #include <asm/asm.h>
 #include <asm/page.h>
 
-#define VERIFY_READ 0
-#define VERIFY_WRITE 1
-
-/*
- * The fs value determines whether argument validity checking should be
- * performed or not.  If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
-
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-
-
-#define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFFUL)
-#define USER_DS                MAKE_MM_SEG(PAGE_OFFSET)
-
-#define get_ds()       (KERNEL_DS)
-#define get_fs()       (current_thread_info()->addr_limit)
-#define set_fs(x)      (current_thread_info()->addr_limit = (x))
-
-#define segment_eq(a, b)       ((a).seg == (b).seg)
-
-/*
- * movsl can be slow when source and dest are not both 8-byte aligned
- */
-#ifdef CONFIG_X86_INTEL_USERCOPY
-extern struct movsl_mask {
-       int mask;
-} ____cacheline_aligned_in_smp movsl_mask;
-#endif
-
-#define __addr_ok(addr)                                        \
-       ((unsigned long __force)(addr) <                \
-        (current_thread_info()->addr_limit.seg))
-
-/*
- * Test whether a block of memory is a valid user space address.
- * Returns 0 if the range is valid, nonzero otherwise.
- *
- * This is equivalent to the following test:
- * (u33)addr + (u33)size >= (u33)current->addr_limit.seg
- *
- * This needs 33-bit arithmetic. We have a carry...
- */
-#define __range_ok(addr, size)                                         \
-({                                                                     \
-       unsigned long flag, roksum;                                     \
-       __chk_user_ptr(addr);                                           \
-       asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0"           \
-           :"=&r" (flag), "=r" (roksum)                                \
-           :"1" (addr), "g" ((int)(size)),                             \
-           "rm" (current_thread_info()->addr_limit.seg));              \
-       flag;                                                           \
-})
-
-/**
- * access_ok: - Checks if a user space pointer is valid
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
- *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
- *        to write to a block, it is always safe to read from it.
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only.  This function may sleep.
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns true (nonzero) if the memory block may be valid, false (zero)
- * if it is definitely invalid.
- *
- * Note that, depending on architecture, this function probably just
- * checks that the pointer is in the user space range - after calling
- * this function, memory access functions may still return -EFAULT.
- */
-#define access_ok(type, addr, size) (likely(__range_ok(addr, size) == 0))
-
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- */
-
-struct exception_table_entry {
-       unsigned long insn, fixup;
-};
-
-extern int fixup_exception(struct pt_regs *regs);
-
-/*
- * These are the main single-value transfer routines.  They automatically
- * use the right size if we just have the right pointer type.
- *
- * This gets kind of ugly. We want to return _two_ values in "get_user()"
- * and yet we don't want to do any pointers, because that is too much
- * of a performance impact. Thus we have a few rather ugly macros here,
- * and hide all the ugliness from the user.
- *
- * The "__xxx" versions of the user access functions are versions that
- * do not verify the address space, that must have been done previously
- * with a separate "access_ok()" call (this is used when we do multiple
- * accesses to the same area of user memory).
- */
-
-extern void __get_user_1(void);
-extern void __get_user_2(void);
-extern void __get_user_4(void);
-
-#define __get_user_x(size, ret, x, ptr)              \
-       asm volatile("call __get_user_" #size \
-                    :"=a" (ret),"=d" (x)     \
-                    :"0" (ptr))
-
-
-/* Careful: we have to cast the result to the type of the pointer
- * for sign reasons */
-
-/**
- * get_user: - Get a simple variable from user space.
- * @x:   Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define get_user(x, ptr)                                               \
-({                                                                     \
-       int __ret_gu;                                                   \
-       unsigned long __val_gu;                                         \
-       __chk_user_ptr(ptr);                                            \
-       switch (sizeof(*(ptr))) {                                       \
-       case 1:                                                         \
-               __get_user_x(1, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       case 2:                                                         \
-               __get_user_x(2, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       case 4:                                                         \
-               __get_user_x(4, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       default:                                                        \
-               __get_user_x(X, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       }                                                               \
-       (x) = (__typeof__(*(ptr)))__val_gu;                             \
-       __ret_gu;                                                       \
-})
-
-extern void __put_user_bad(void);
-
-/*
- * Strange magic calling convention: pointer in %ecx,
- * value in %eax(:%edx), return value in %eax, no clobbers.
- */
-extern void __put_user_1(void);
-extern void __put_user_2(void);
-extern void __put_user_4(void);
-extern void __put_user_8(void);
-
-#define __put_user_1(x, ptr)                                   \
-       asm volatile("call __put_user_1" : "=a" (__ret_pu)      \
-                    : "0" ((typeof(*(ptr)))(x)), "c" (ptr))
-
-#define __put_user_2(x, ptr)                                   \
-       asm volatile("call __put_user_2" : "=a" (__ret_pu)      \
-                    : "0" ((typeof(*(ptr)))(x)), "c" (ptr))
-
-#define __put_user_4(x, ptr)                                   \
-       asm volatile("call __put_user_4" : "=a" (__ret_pu)      \
-                    : "0" ((typeof(*(ptr)))(x)), "c" (ptr))
-
-#define __put_user_8(x, ptr)                                   \
-       asm volatile("call __put_user_8" : "=a" (__ret_pu)      \
-                    : "A" ((typeof(*(ptr)))(x)), "c" (ptr))
-
-#define __put_user_X(x, ptr)                                   \
-       asm volatile("call __put_user_X" : "=a" (__ret_pu)      \
-                    : "c" (ptr))
-
-/**
- * put_user: - Write a simple value into user space.
- * @x:   Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#ifdef CONFIG_X86_WP_WORKS_OK
-
-#define put_user(x, ptr)                                       \
-({                                                             \
-       int __ret_pu;                                           \
-       __typeof__(*(ptr)) __pu_val;                            \
-       __chk_user_ptr(ptr);                                    \
-       __pu_val = x;                                           \
-       switch (sizeof(*(ptr))) {                               \
-       case 1:                                                 \
-               __put_user_1(__pu_val, ptr);                    \
-               break;                                          \
-       case 2:                                                 \
-               __put_user_2(__pu_val, ptr);                    \
-               break;                                          \
-       case 4:                                                 \
-               __put_user_4(__pu_val, ptr);                    \
-               break;                                          \
-       case 8:                                                 \
-               __put_user_8(__pu_val, ptr);                    \
-               break;                                          \
-       default:                                                \
-               __put_user_X(__pu_val, ptr);                    \
-               break;                                          \
-       }                                                       \
-       __ret_pu;                                               \
-})
-
-#else
-#define put_user(x, ptr)                                       \
-({                                                             \
-       int __ret_pu;                                           \
-       __typeof__(*(ptr))__pus_tmp = x;                        \
-       __ret_pu = 0;                                           \
-       if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp,         \
-                                      sizeof(*(ptr))) != 0))   \
-               __ret_pu = -EFAULT;                             \
-       __ret_pu;                                               \
-})
-
-
-#endif
-
-/**
- * __get_user: - Get a simple variable from user space, with less checking.
- * @x:   Variable to store result.
- * @ptr: Source address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple variable from user space to kernel
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and the result of
- * dereferencing @ptr must be assignable to @x without a cast.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- * On error, the variable @x is set to zero.
- */
-#define __get_user(x, ptr)                             \
-       __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
-
-
-/**
- * __put_user: - Write a simple value into user space, with less checking.
- * @x:   Value to copy to user space.
- * @ptr: Destination address, in user space.
- *
- * Context: User context only.  This function may sleep.
- *
- * This macro copies a single simple value from kernel space to user
- * space.  It supports simple types like char and int, but not larger
- * data types like structures or arrays.
- *
- * @ptr must have pointer-to-simple-variable type, and @x must be assignable
- * to the result of dereferencing @ptr.
- *
- * Caller must check the pointer with access_ok() before calling this
- * function.
- *
- * Returns zero on success, or -EFAULT on error.
- */
-#define __put_user(x, ptr)                                             \
-       __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
-
-#define __put_user_nocheck(x, ptr, size)                       \
-({                                                             \
-       long __pu_err;                                          \
-       __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \
-       __pu_err;                                               \
-})
-
-
-#define __put_user_u64(x, addr, err)                                   \
-       asm volatile("1:        movl %%eax,0(%2)\n"                     \
-                    "2:        movl %%edx,4(%2)\n"                     \
-                    "3:\n"                                             \
-                    ".section .fixup,\"ax\"\n"                         \
-                    "4:        movl %3,%0\n"                           \
-                    "  jmp 3b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE(1b, 4b)                               \
-                    _ASM_EXTABLE(2b, 4b)                               \
-                    : "=r" (err)                                       \
-                    : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err))
-
-#ifdef CONFIG_X86_WP_WORKS_OK
-
-#define __put_user_size(x, ptr, size, retval, errret)                  \
-do {                                                                   \
-       retval = 0;                                                     \
-       __chk_user_ptr(ptr);                                            \
-       switch (size) {                                                 \
-       case 1:                                                         \
-               __put_user_asm(x, ptr, retval, "b", "b", "iq", errret); \
-               break;                                                  \
-       case 2:                                                         \
-               __put_user_asm(x, ptr, retval, "w", "w", "ir", errret); \
-               break;                                                  \
-       case 4:                                                         \
-               __put_user_asm(x, ptr, retval, "l", "",  "ir", errret); \
-               break;                                                  \
-       case 8:                                                         \
-               __put_user_u64((__typeof__(*ptr))(x), ptr, retval);     \
-               break;                                                  \
-       default:                                                        \
-               __put_user_bad();                                       \
-       }                                                               \
-} while (0)
-
-#else
-
-#define __put_user_size(x, ptr, size, retval, errret)                  \
-do {                                                                   \
-       __typeof__(*(ptr))__pus_tmp = x;                                \
-       retval = 0;                                                     \
-                                                                       \
-       if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0))    \
-               retval = errret;                                        \
-} while (0)
-
-#endif
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct __user *)(x))
-
-/*
- * Tell gcc we read from memory instead of writing: this is because
- * we do not write to any memory gcc knows about, so there are no
- * aliasing issues.
- */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
-       asm volatile("1:        mov"itype" %"rtype"1,%2\n"              \
-                    "2:\n"                                             \
-                    ".section .fixup,\"ax\"\n"                         \
-                    "3:        movl %3,%0\n"                           \
-                    "  jmp 2b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE(1b, 3b)                               \
-                    : "=r"(err)                                        \
-                    : ltype (x), "m" (__m(addr)), "i" (errret), "0" (err))
-
-
-#define __get_user_nocheck(x, ptr, size)                               \
-({                                                                     \
-       long __gu_err;                                                  \
-       unsigned long __gu_val;                                         \
-       __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);    \
-       (x) = (__typeof__(*(ptr)))__gu_val;                             \
-       __gu_err;                                                       \
-})
-
-extern long __get_user_bad(void);
-
-#define __get_user_size(x, ptr, size, retval, errret)                  \
-do {                                                                   \
-       retval = 0;                                                     \
-       __chk_user_ptr(ptr);                                            \
-       switch (size) {                                                 \
-       case 1:                                                         \
-               __get_user_asm(x, ptr, retval, "b", "b", "=q", errret); \
-               break;                                                  \
-       case 2:                                                         \
-               __get_user_asm(x, ptr, retval, "w", "w", "=r", errret); \
-               break;                                                  \
-       case 4:                                                         \
-               __get_user_asm(x, ptr, retval, "l", "", "=r", errret);  \
-               break;                                                  \
-       default:                                                        \
-               (x) = __get_user_bad();                                 \
-       }                                                               \
-} while (0)
-
-#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret)      \
-       asm volatile("1:        mov"itype" %2,%"rtype"1\n"              \
-                    "2:\n"                                             \
-                    ".section .fixup,\"ax\"\n"                         \
-                    "3:        movl %3,%0\n"                           \
-                    "  xor"itype" %"rtype"1,%"rtype"1\n"               \
-                    "  jmp 2b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE(1b, 3b)                               \
-                    : "=r" (err), ltype (x)                            \
-                    : "m" (__m(addr)), "i" (errret), "0" (err))
-
-
 unsigned long __must_check __copy_to_user_ll
                (void __user *to, const void *from, unsigned long n);
 unsigned long __must_check __copy_from_user_ll
@@ -576,8 +156,6 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
        return __copy_from_user_ll(to, from, n);
 }
 
-#define ARCH_HAS_NOCACHE_UACCESS
-
 static __always_inline unsigned long __copy_from_user_nocache(void *to,
                                const void __user *from, unsigned long n)
 {
index b8a2f43399032e1ce617e38a35eb28919f08a287..515d4dce96b598bc6e9d07dba21332a44924948c 100644 (file)
@@ -9,265 +9,6 @@
 #include <linux/prefetch.h>
 #include <asm/page.h>
 
-#define VERIFY_READ 0
-#define VERIFY_WRITE 1
-
-/*
- * The fs value determines whether argument validity checking should be
- * performed or not.  If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
-
-#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-
-#define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFFFFFFFFFFUL)
-#define USER_DS                MAKE_MM_SEG(PAGE_OFFSET)
-
-#define get_ds()       (KERNEL_DS)
-#define get_fs()       (current_thread_info()->addr_limit)
-#define set_fs(x)      (current_thread_info()->addr_limit = (x))
-
-#define segment_eq(a, b)       ((a).seg == (b).seg)
-
-#define __addr_ok(addr) (!((unsigned long)(addr) &                     \
-                          (current_thread_info()->addr_limit.seg)))
-
-/*
- * Uhhuh, this needs 65-bit arithmetic. We have a carry..
- */
-#define __range_not_ok(addr, size)                                     \
-({                                                                     \
-       unsigned long flag, roksum;                                     \
-       __chk_user_ptr(addr);                                           \
-       asm("# range_ok\n\r"                                            \
-           "addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0"         \
-           : "=&r" (flag), "=r" (roksum)                               \
-           : "1" (addr), "g" ((long)(size)),                           \
-             "g" (current_thread_info()->addr_limit.seg));             \
-       flag;                                                           \
-})
-
-#define access_ok(type, addr, size) (__range_not_ok(addr, size) == 0)
-
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- */
-
-struct exception_table_entry {
-       unsigned long insn, fixup;
-};
-
-extern int fixup_exception(struct pt_regs *regs);
-
-#define ARCH_HAS_SEARCH_EXTABLE
-
-/*
- * These are the main single-value transfer routines.  They automatically
- * use the right size if we just have the right pointer type.
- *
- * This gets kind of ugly. We want to return _two_ values in "get_user()"
- * and yet we don't want to do any pointers, because that is too much
- * of a performance impact. Thus we have a few rather ugly macros here,
- * and hide all the ugliness from the user.
- *
- * The "__xxx" versions of the user access functions are versions that
- * do not verify the address space, that must have been done previously
- * with a separate "access_ok()" call (this is used when we do multiple
- * accesses to the same area of user memory).
- */
-
-#define __get_user_x(size, ret, x, ptr)                      \
-       asm volatile("call __get_user_" #size         \
-                    : "=a" (ret),"=d" (x)            \
-                    : "c" (ptr)                      \
-                    : "r8")
-
-/* Careful: we have to cast the result to the type of the pointer
- * for sign reasons */
-
-#define get_user(x, ptr)                                               \
-({                                                                     \
-       unsigned long __val_gu;                                         \
-       int __ret_gu;                                                   \
-       __chk_user_ptr(ptr);                                            \
-       switch (sizeof(*(ptr))) {                                       \
-       case 1:                                                         \
-               __get_user_x(1, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       case 2:                                                         \
-               __get_user_x(2, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       case 4:                                                         \
-               __get_user_x(4, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       case 8:                                                         \
-               __get_user_x(8, __ret_gu, __val_gu, ptr);               \
-               break;                                                  \
-       default:                                                        \
-               __get_user_bad();                                       \
-               break;                                                  \
-       }                                                               \
-       (x) = (__force typeof(*(ptr)))__val_gu;                         \
-       __ret_gu;                                                       \
-})
-
-extern void __put_user_1(void);
-extern void __put_user_2(void);
-extern void __put_user_4(void);
-extern void __put_user_8(void);
-extern void __put_user_bad(void);
-
-#define __put_user_x(size, ret, x, ptr)                                        \
-       asm volatile("call __put_user_" #size                           \
-                    :"=a" (ret)                                        \
-                    :"c" (ptr),"d" (x)                                 \
-                    :"r8")
-
-#define put_user(x, ptr)                                               \
-       __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
-
-#define __get_user(x, ptr)                                             \
-       __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
-#define __put_user(x, ptr)                                             \
-       __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
-
-#define __get_user_unaligned __get_user
-#define __put_user_unaligned __put_user
-
-#define __put_user_nocheck(x, ptr, size)               \
-({                                                     \
-       int __pu_err;                                   \
-       __put_user_size((x), (ptr), (size), __pu_err);  \
-       __pu_err;                                       \
-})
-
-
-#define __put_user_check(x, ptr, size)                         \
-({                                                             \
-       int __pu_err;                                           \
-       typeof(*(ptr)) __user *__pu_addr = (ptr);               \
-       switch (size) {                                         \
-       case 1:                                                 \
-               __put_user_x(1, __pu_err, x, __pu_addr);        \
-               break;                                          \
-       case 2:                                                 \
-               __put_user_x(2, __pu_err, x, __pu_addr);        \
-               break;                                          \
-       case 4:                                                 \
-               __put_user_x(4, __pu_err, x, __pu_addr);        \
-               break;                                          \
-       case 8:                                                 \
-               __put_user_x(8, __pu_err, x, __pu_addr);        \
-               break;                                          \
-       default:                                                \
-               __put_user_bad();                               \
-       }                                                       \
-       __pu_err;                                               \
-})
-
-#define __put_user_size(x, ptr, size, retval)                          \
-do {                                                                   \
-       retval = 0;                                                     \
-       __chk_user_ptr(ptr);                                            \
-       switch (size) {                                                 \
-       case 1:                                                         \
-               __put_user_asm(x, ptr, retval, "b", "b", "iq", -EFAULT);\
-               break;                                                  \
-       case 2:                                                         \
-               __put_user_asm(x, ptr, retval, "w", "w", "ir", -EFAULT);\
-               break;                                                  \
-       case 4:                                                         \
-               __put_user_asm(x, ptr, retval, "l", "k", "ir", -EFAULT);\
-               break;                                                  \
-       case 8:                                                         \
-               __put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT); \
-               break;                                                  \
-       default:                                                        \
-               __put_user_bad();                                       \
-       }                                                               \
-} while (0)
-
-/* FIXME: this hack is definitely wrong -AK */
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct __user *)(x))
-
-/*
- * Tell gcc we read from memory instead of writing: this is because
- * we do not write to any memory gcc knows about, so there are no
- * aliasing issues.
- */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno)       \
-       asm volatile("1:        mov"itype" %"rtype"1,%2\n"              \
-                    "2:\n"                                             \
-                    ".section .fixup, \"ax\"\n"                        \
-                    "3:        mov %3,%0\n"                            \
-                    "  jmp 2b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE(1b, 3b)                               \
-                    : "=r"(err)                                        \
-                    : ltype (x), "m" (__m(addr)), "i" (errno), "0" (err))
-
-
-#define __get_user_nocheck(x, ptr, size)                       \
-({                                                             \
-       int __gu_err;                                           \
-       unsigned long __gu_val;                                 \
-       __get_user_size(__gu_val, (ptr), (size), __gu_err);     \
-       (x) = (__force typeof(*(ptr)))__gu_val;                 \
-       __gu_err;                                               \
-})
-
-extern int __get_user_1(void);
-extern int __get_user_2(void);
-extern int __get_user_4(void);
-extern int __get_user_8(void);
-extern int __get_user_bad(void);
-
-#define __get_user_size(x, ptr, size, retval)                          \
-do {                                                                   \
-       retval = 0;                                                     \
-       __chk_user_ptr(ptr);                                            \
-       switch (size) {                                                 \
-       case 1:                                                         \
-               __get_user_asm(x, ptr, retval, "b", "b", "=q", -EFAULT);\
-               break;                                                  \
-       case 2:                                                         \
-               __get_user_asm(x, ptr, retval, "w", "w", "=r", -EFAULT);\
-               break;                                                  \
-       case 4:                                                         \
-               __get_user_asm(x, ptr, retval, "l", "k", "=r", -EFAULT);\
-               break;                                                  \
-       case 8:                                                         \
-               __get_user_asm(x, ptr, retval, "q", "", "=r", -EFAULT); \
-               break;                                                  \
-       default:                                                        \
-               (x) = __get_user_bad();                                 \
-       }                                                               \
-} while (0)
-
-#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno)       \
-       asm volatile("1:        mov"itype" %2,%"rtype"1\n"              \
-                    "2:\n"                                             \
-                    ".section .fixup, \"ax\"\n"                        \
-                    "3:        mov %3,%0\n"                            \
-                    "  xor"itype" %"rtype"1,%"rtype"1\n"               \
-                    "  jmp 2b\n"                                       \
-                    ".previous\n"                                      \
-                    _ASM_EXTABLE(1b, 3b)                               \
-                    : "=r" (err), ltype (x)                            \
-                    : "m" (__m(addr)), "i"(errno), "0"(err))
-
 /*
  * Copy To/From Userspace
  */
@@ -437,7 +178,6 @@ __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
        return copy_user_generic((__force void *)dst, src, size);
 }
 
-#define ARCH_HAS_NOCACHE_UACCESS 1
 extern long __copy_user_nocache(void *dst, const void __user *src,
                                unsigned size, int zerorest);
 
@@ -455,4 +195,7 @@ static inline int __copy_from_user_inatomic_nocache(void *dst,
        return __copy_user_nocache(dst, src, size, 0);
 }
 
+unsigned long
+copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest);
+
 #endif /* __X86_64_UACCESS_H */
index fe26e36d0f5131aa4f2a8623a6ed45d5b92faaad..9c1a4a3470d96441d4bd194d12ff5541b321d135 100644 (file)
@@ -290,7 +290,7 @@ __SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
 #define __NR_rt_sigqueueinfo                   129
 __SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
 #define __NR_rt_sigsuspend                     130
-__SYSCALL(__NR_rt_sigsuspend, stub_rt_sigsuspend)
+__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend)
 #define __NR_sigaltstack                       131
 __SYSCALL(__NR_sigaltstack, stub_sigaltstack)
 #define __NR_utime                             132
diff --git a/include/asm-x86/uv/uv_bau.h b/include/asm-x86/uv/uv_bau.h
new file mode 100644 (file)
index 0000000..91ac0df
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ *
+ * SGI UV Broadcast Assist Unit definitions
+ *
+ * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef __ASM_X86_UV_BAU__
+#define __ASM_X86_UV_BAU__
+
+#include <linux/bitmap.h>
+#define BITSPERBYTE 8
+
+/*
+ * Broadcast Assist Unit messaging structures
+ *
+ * Selective Broadcast activations are induced by software action
+ * specifying a particular 8-descriptor "set" via a 6-bit index written
+ * to an MMR.
+ * Thus there are 64 unique 512-byte sets of SB descriptors - one set for
+ * each 6-bit index value. These descriptor sets are mapped in sequence
+ * starting with set 0 located at the address specified in the
+ * BAU_SB_DESCRIPTOR_BASE register, set 1 is located at BASE + 512,
+ * set 2 is at BASE + 2*512, set 3 at BASE + 3*512, and so on.
+ *
+ * We will use 31 sets, one for sending BAU messages from each of the 32
+ * cpu's on the node.
+ *
+ * TLB shootdown will use the first of the 8 descriptors of each set.
+ * Each of the descriptors is 64 bytes in size (8*64 = 512 bytes in a set).
+ */
+
+#define UV_ITEMS_PER_DESCRIPTOR                8
+#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_DISTRIBUTION_SIZE           256
+#define UV_SW_ACK_NPENDING             8
+#define UV_BAU_MESSAGE                 200
+/*
+ * Messaging irq; see irq_64.h and include/asm-x86/hw_irq_64.h
+ * To be dynamically allocated in the future
+ */
+#define UV_NET_ENDPOINT_INTD           0x38
+#define UV_DESC_BASE_PNODE_SHIFT       49
+#define UV_PAYLOADQ_PNODE_SHIFT                49
+#define UV_PTC_BASENAME                        "sgi_uv/ptc_statistics"
+#define uv_physnodeaddr(x)             ((__pa((unsigned long)(x)) & uv_mmask))
+
+/*
+ * bits in UVH_LB_BAU_SB_ACTIVATION_STATUS_0/1
+ */
+#define DESC_STATUS_IDLE               0
+#define DESC_STATUS_ACTIVE             1
+#define DESC_STATUS_DESTINATION_TIMEOUT        2
+#define DESC_STATUS_SOURCE_TIMEOUT     3
+
+/*
+ * source side threshholds at which message retries print a warning
+ */
+#define SOURCE_TIMEOUT_LIMIT           20
+#define DESTINATION_TIMEOUT_LIMIT      20
+
+/*
+ * number of entries in the destination side payload queue
+ */
+#define DEST_Q_SIZE                    17
+/*
+ * number of destination side software ack resources
+ */
+#define DEST_NUM_RESOURCES             8
+#define MAX_CPUS_PER_NODE              32
+/*
+ * completion statuses for sending a TLB flush message
+ */
+#define        FLUSH_RETRY                     1
+#define        FLUSH_GIVEUP                    2
+#define        FLUSH_COMPLETE                  3
+
+/*
+ * Distribution: 32 bytes (256 bits) (bytes 0-0x1f of descriptor)
+ * If the 'multilevel' flag in the header portion of the descriptor
+ * has been set to 0, then endpoint multi-unicast mode is selected.
+ * The distribution specification (32 bytes) is interpreted as a 256-bit
+ * distribution vector. Adjacent bits correspond to consecutive even numbered
+ * nodeIDs. The result of adding the index of a given bit to the 15-bit
+ * 'base_dest_nodeid' field of the header corresponds to the
+ * destination nodeID associated with that specified bit.
+ */
+struct bau_target_nodemask {
+       unsigned long bits[BITS_TO_LONGS(256)];
+};
+
+/*
+ * mask of cpu's on a node
+ * (during initialization we need to check that unsigned long has
+ *  enough bits for max. cpu's per node)
+ */
+struct bau_local_cpumask {
+       unsigned long bits;
+};
+
+/*
+ * Payload: 16 bytes (128 bits) (bytes 0x20-0x2f of descriptor)
+ * only 12 bytes (96 bits) of the payload area are usable.
+ * An additional 3 bytes (bits 27:4) of the header address are carried
+ * to the next bytes of the destination payload queue.
+ * And an additional 2 bytes of the header Suppl_A field are also
+ * carried to the destination payload queue.
+ * But the first byte of the Suppl_A becomes bits 127:120 (the 16th byte)
+ * of the destination payload queue, which is written by the hardware
+ * with the s/w ack resource bit vector.
+ * [ effective message contents (16 bytes (128 bits) maximum), not counting
+ *   the s/w ack bit vector  ]
+ */
+
+/*
+ * The payload is software-defined for INTD transactions
+ */
+struct bau_msg_payload {
+       unsigned long address;          /* signifies a page or all TLB's
+                                               of the cpu */
+       /* 64 bits */
+       unsigned short sending_cpu;     /* filled in by sender */
+       /* 16 bits */
+       unsigned short acknowledge_count;/* filled in by destination */
+       /* 16 bits */
+       unsigned int reserved1:32;      /* not usable */
+};
+
+
+/*
+ * Message header:  16 bytes (128 bits) (bytes 0x30-0x3f of descriptor)
+ * see table 4.2.3.0.1 in broacast_assist spec.
+ */
+struct bau_msg_header {
+       int dest_subnodeid:6;   /* must be zero */
+       /* bits 5:0 */
+       int base_dest_nodeid:15; /* nasid>>1 (pnode) of first bit in node_map */
+       /* bits 20:6 */
+       int command:8;          /* message type */
+       /* bits 28:21 */
+                               /* 0x38: SN3net EndPoint Message */
+       int rsvd_1:3;           /* must be zero */
+       /* bits 31:29 */
+                               /* int will align on 32 bits */
+       int rsvd_2:9;           /* must be zero */
+       /* bits 40:32 */
+                               /* Suppl_A is 56-41 */
+       int payload_2a:8;       /* becomes byte 16 of msg */
+       /* bits 48:41 */        /* not currently using */
+       int payload_2b:8;       /* becomes byte 17 of msg */
+       /* bits 56:49 */        /* not currently using */
+                               /* Address field (96:57) is never used as an
+                                  address (these are address bits 42:3) */
+       int rsvd_3:1;           /* must be zero */
+       /* bit 57 */
+                               /* address bits 27:4 are payload */
+                               /* these 24 bits become bytes 12-14 of msg */
+       int replied_to:1;       /* sent as 0 by the source to byte 12 */
+       /* bit 58 */
+
+       int payload_1a:5;       /* not currently used */
+       /* bits 63:59 */
+       int payload_1b:8;       /* not currently used */
+       /* bits 71:64 */
+       int payload_1c:8;       /* not currently used */
+       /* bits 79:72 */
+       int payload_1d:2;       /* not currently used */
+       /* bits 81:80 */
+
+       int rsvd_4:7;           /* must be zero */
+       /* bits 88:82 */
+       int sw_ack_flag:1;      /* software acknowledge flag */
+       /* bit 89 */
+                               /* INTD trasactions at destination are to
+                                  wait for software acknowledge */
+       int rsvd_5:6;           /* must be zero */
+       /* bits 95:90 */
+       int rsvd_6:5;           /* must be zero */
+       /* bits 100:96 */
+       int int_both:1;         /* if 1, interrupt both sockets on the blade */
+       /* bit 101*/
+       int fairness:3;         /* usually zero */
+       /* bits 104:102 */
+       int multilevel:1;       /* multi-level multicast format */
+       /* bit 105 */
+                               /* 0 for TLB: endpoint multi-unicast messages */
+       int chaining:1;         /* next descriptor is part of this activation*/
+       /* bit 106 */
+       int rsvd_7:21;          /* must be zero */
+       /* bits 127:107 */
+};
+
+/*
+ * The activation descriptor:
+ * The format of the message to send, plus all accompanying control
+ * Should be 64 bytes
+ */
+struct bau_desc {
+       struct bau_target_nodemask distribution;
+       /*
+        * message template, consisting of header and payload:
+        */
+       struct bau_msg_header header;
+       struct bau_msg_payload payload;
+};
+/*
+ *   -payload--    ---------header------
+ *   bytes 0-11    bits 41-56  bits 58-81
+ *       A           B  (2)      C (3)
+ *
+ *            A/B/C are moved to:
+ *       A            C          B
+ *   bytes 0-11  bytes 12-14  bytes 16-17  (byte 15 filled in by hw as vector)
+ *   ------------payload queue-----------
+ */
+
+/*
+ * The payload queue on the destination side is an array of these.
+ * With BAU_MISC_CONTROL set for software acknowledge mode, the messages
+ * are 32 bytes (2 micropackets) (256 bits) in length, but contain only 17
+ * bytes of usable data, including the sw ack vector in byte 15 (bits 127:120)
+ * (12 bytes come from bau_msg_payload, 3 from payload_1, 2 from
+ *  sw_ack_vector and payload_2)
+ * "Enabling Software Acknowledgment mode (see Section 4.3.3 Software
+ *  Acknowledge Processing) also selects 32 byte (17 bytes usable) payload
+ *  operation."
+ */
+struct bau_payload_queue_entry {
+       unsigned long address;          /* signifies a page or all TLB's
+                                               of the cpu */
+       /* 64 bits, bytes 0-7 */
+
+       unsigned short sending_cpu;     /* cpu that sent the message */
+       /* 16 bits, bytes 8-9 */
+
+       unsigned short acknowledge_count; /* filled in by destination */
+       /* 16 bits, bytes 10-11 */
+
+       unsigned short replied_to:1;    /* sent as 0 by the source */
+       /* 1 bit */
+       unsigned short unused1:7;       /* not currently using */
+       /* 7 bits: byte 12) */
+
+       unsigned char unused2[2];       /* not currently using */
+       /* bytes 13-14 */
+
+       unsigned char sw_ack_vector;    /* filled in by the hardware */
+       /* byte 15 (bits 127:120) */
+
+       unsigned char unused4[3];       /* not currently using bytes 17-19 */
+       /* bytes 17-19 */
+
+       int number_of_cpus;             /* filled in at destination */
+       /* 32 bits, bytes 20-23 (aligned) */
+
+       unsigned char unused5[8];       /* not using */
+       /* bytes 24-31 */
+};
+
+/*
+ * one for every slot in the destination payload queue
+ */
+struct bau_msg_status {
+       struct bau_local_cpumask seen_by;       /* map of cpu's */
+};
+
+/*
+ * one for every slot in the destination software ack resources
+ */
+struct bau_sw_ack_status {
+       struct bau_payload_queue_entry *msg;    /* associated message */
+       int watcher;                            /* cpu monitoring, or -1 */
+};
+
+/*
+ * one on every node and per-cpu; to locate the software tables
+ */
+struct bau_control {
+       struct bau_desc *descriptor_base;
+       struct bau_payload_queue_entry *bau_msg_head;
+       struct bau_payload_queue_entry *va_queue_first;
+       struct bau_payload_queue_entry *va_queue_last;
+       struct bau_msg_status *msg_statuses;
+       int *watching; /* pointer to array */
+};
+
+/*
+ * This structure is allocated per_cpu for UV TLB shootdown statistics.
+ */
+struct ptc_stats {
+       unsigned long ptc_i;    /* number of IPI-style flushes */
+       unsigned long requestor;        /* number of nodes this cpu sent to */
+       unsigned long requestee;        /* times cpu was remotely requested */
+       unsigned long alltlb;   /* times all tlb's on this cpu were flushed */
+       unsigned long onetlb;   /* times just one tlb on this cpu was flushed */
+       unsigned long s_retry;  /* retries on source side timeouts */
+       unsigned long d_retry;  /* retries on destination side timeouts */
+       unsigned long sflush;   /* cycles spent in uv_flush_tlb_others */
+       unsigned long dflush;   /* cycles spent on destination side */
+       unsigned long retriesok; /* successes on retries */
+       unsigned long nomsg;    /* interrupts with no message */
+       unsigned long multmsg;  /* interrupts with multiple messages */
+       unsigned long ntargeted;/* nodes targeted */
+};
+
+static inline int bau_node_isset(int node, struct bau_target_nodemask *dstp)
+{
+       return constant_test_bit(node, &dstp->bits[0]);
+}
+static inline void bau_node_set(int node, struct bau_target_nodemask *dstp)
+{
+       __set_bit(node, &dstp->bits[0]);
+}
+static inline void bau_nodes_clear(struct bau_target_nodemask *dstp, int nbits)
+{
+       bitmap_zero(&dstp->bits[0], nbits);
+}
+
+static inline void bau_cpubits_clear(struct bau_local_cpumask *dstp, int nbits)
+{
+       bitmap_zero(&dstp->bits, nbits);
+}
+
+#define cpubit_isset(cpu, bau_local_cpumask) \
+       test_bit((cpu), (bau_local_cpumask).bits)
+
+extern int uv_flush_tlb_others(cpumask_t *, struct mm_struct *, unsigned long);
+extern void uv_bau_message_intr1(void);
+extern void uv_bau_timeout_intr1(void);
+
+#endif /* __ASM_X86_UV_BAU__ */
index 26b9240d1e2359de995da011c180e5fda2b9e3d9..a4ef26e5850bb445e5dfa5493b1778ee85feb771 100644 (file)
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef __ASM_X86_UV_HUB_H__
 /*
  * Addressing Terminology
  *
- *     NASID - network ID of a router, Mbrick or Cbrick. Nasid values of
- *             routers always have low bit of 1, C/MBricks have low bit
- *             equal to 0. Most addressing macros that target UV hub chips
- *             right shift the NASID by 1 to exclude the always-zero bit.
+ *     M       - The low M bits of a physical address represent the offset
+ *               into the blade local memory. RAM memory on a blade is physically
+ *               contiguous (although various IO spaces may punch holes in
+ *               it)..
  *
- *     SNASID - NASID right shifted by 1 bit.
+ *     N       - Number of bits in the node portion of a socket physical
+ *               address.
+ *
+ *     NASID   - network ID of a router, Mbrick or Cbrick. Nasid values of
+ *               routers always have low bit of 1, C/MBricks have low bit
+ *               equal to 0. Most addressing macros that target UV hub chips
+ *               right shift the NASID by 1 to exclude the always-zero bit.
+ *               NASIDs contain up to 15 bits.
+ *
+ *     GNODE   - NASID right shifted by 1 bit. Most mmrs contain gnodes instead
+ *               of nasids.
+ *
+ *     PNODE   - the low N bits of the GNODE. The PNODE is the most useful variant
+ *               of the nasid for socket usage.
+ *
+ *
+ *  NumaLink Global Physical Address Format:
+ *  +--------------------------------+---------------------+
+ *  |00..000|      GNODE             |      NodeOffset     |
+ *  +--------------------------------+---------------------+
+ *          |<-------53 - M bits --->|<--------M bits ----->
+ *
+ *     M - number of node offset bits (35 .. 40)
  *
  *
  *  Memory/UV-HUB Processor Socket Address Format:
- *  +--------+---------------+---------------------+
- *  |00..0000|    SNASID     |      NodeOffset     |
- *  +--------+---------------+---------------------+
- *           <--- N bits --->|<--------M bits ----->
+ *  +----------------+---------------+---------------------+
+ *  |00..000000000000|   PNODE       |      NodeOffset     |
+ *  +----------------+---------------+---------------------+
+ *                   <--- N bits --->|<--------M bits ----->
  *
- *     M number of node offset bits (35 .. 40)
- *     N number of SNASID bits (0 .. 10)
+ *     M number of node offset bits (35 .. 40)
+ *     N - number of PNODE bits (0 .. 10)
  *
  *             Note: M + N cannot currently exceed 44 (x86_64) or 46 (IA64).
  *             The actual values are configuration dependent and are set at
- *             boot time
+ *             boot time. M & N values are set by the hardware/BIOS at boot.
+ *
  *
  * APICID format
  *     NOTE!!!!!! This is the current format of the APICID. However, code
  *
  *             1111110000000000
  *             5432109876543210
- *             nnnnnnnnnnlc0cch
+ *             pppppppppplc0cch
  *             sssssssssss
  *
- *                     n  = snasid bits
+ *                     p  = pnode bits
  *                     l =  socket number on board
  *                     c  = core
  *                     h  = hyperthread
- *                     s  = bits that are in the socket CSR
+ *                     s  = bits that are in the SOCKET_ID CSR
  *
  *     Note: Processor only supports 12 bits in the APICID register. The ACPI
  *           tables hold all 16 bits. Software needs to be aware of this.
@@ -74,7 +97,7 @@
  * This value is also the value of the maximum number of non-router NASIDs
  * in the numalink fabric.
  *
- * NOTE: a brick may be 1 or 2 OS nodes. Don't get these confused.
+ * NOTE: a brick may contain 1 or 2 OS nodes. Don't get these confused.
  */
 #define UV_MAX_NUMALINK_BLADES 16384
 
  */
 struct uv_hub_info_s {
        unsigned long   global_mmr_base;
-       unsigned short  local_nasid;
-       unsigned short  gnode_upper;
+       unsigned long   gpa_mask;
+       unsigned long   gnode_upper;
+       unsigned long   lowmem_remap_top;
+       unsigned long   lowmem_remap_base;
+       unsigned short  pnode;
+       unsigned short  pnode_mask;
        unsigned short  coherency_domain_number;
        unsigned short  numa_blade_id;
        unsigned char   blade_processor_id;
@@ -112,83 +139,126 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
  * Local & Global MMR space macros.
  *     Note: macros are intended to be used ONLY by inline functions
  *     in this file - not by other kernel code.
+ *             n -  NASID (full 15-bit global nasid)
+ *             g -  GNODE (full 15-bit global nasid, right shifted 1)
+ *             p -  PNODE (local part of nsids, right shifted 1)
  */
-#define UV_SNASID(n)                   ((n) >> 1)
-#define UV_NASID(n)                    ((n) << 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_LOCAL_MMR_BASE              0xf4000000UL
 #define UV_GLOBAL_MMR32_BASE           0xf8000000UL
 #define UV_GLOBAL_MMR64_BASE           (uv_hub_info->global_mmr_base)
+#define UV_LOCAL_MMR_SIZE              (64UL * 1024 * 1024)
+#define UV_GLOBAL_MMR32_SIZE           (64UL * 1024 * 1024)
 
-#define UV_GLOBAL_MMR32_SNASID_MASK    0x3ff
-#define UV_GLOBAL_MMR32_SNASID_SHIFT   15
-#define UV_GLOBAL_MMR64_SNASID_SHIFT   26
+#define UV_GLOBAL_MMR32_PNODE_SHIFT    15
+#define UV_GLOBAL_MMR64_PNODE_SHIFT    26
 
-#define UV_GLOBAL_MMR32_NASID_BITS(n)                                  \
-               (((UV_SNASID(n) & UV_GLOBAL_MMR32_SNASID_MASK)) <<      \
-               (UV_GLOBAL_MMR32_SNASID_SHIFT))
+#define UV_GLOBAL_MMR32_PNODE_BITS(p)  ((p) << (UV_GLOBAL_MMR32_PNODE_SHIFT))
 
-#define UV_GLOBAL_MMR64_NASID_BITS(n)                                  \
-       ((unsigned long)UV_SNASID(n) << UV_GLOBAL_MMR64_SNASID_SHIFT)
+#define UV_GLOBAL_MMR64_PNODE_BITS(p)                                  \
+       ((unsigned long)(p) << UV_GLOBAL_MMR64_PNODE_SHIFT)
+
+#define UV_APIC_PNODE_SHIFT    6
+
+/*
+ * Macros for converting between kernel virtual addresses, socket local physical
+ * addresses, and UV global physical addresses.
+ *     Note: use the standard __pa() & __va() macros for converting
+ *           between socket virtual and socket physical addresses.
+ */
+
+/* socket phys RAM --> UV global physical address */
+static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr)
+{
+       if (paddr < uv_hub_info->lowmem_remap_top)
+               paddr += uv_hub_info->lowmem_remap_base;
+       return paddr | uv_hub_info->gnode_upper;
+}
+
+
+/* socket virtual --> UV global physical address */
+static inline unsigned long uv_gpa(void *v)
+{
+       return __pa(v) | uv_hub_info->gnode_upper;
+}
+
+/* socket virtual --> UV global physical address */
+static inline void *uv_vgpa(void *v)
+{
+       return (void *)uv_gpa(v);
+}
+
+/* UV global physical address --> socket virtual */
+static inline void *uv_va(unsigned long gpa)
+{
+       return __va(gpa & uv_hub_info->gpa_mask);
+}
+
+/* pnode, offset --> socket virtual */
+static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
+{
+       return __va(((unsigned long)pnode << uv_hub_info->m_val) | offset);
+}
 
-#define UV_APIC_NASID_SHIFT    6
 
 /*
- * Extract a NASID from an APICID (full apicid, not processor subset)
+ * Extract a PNODE from an APICID (full apicid, not processor subset)
  */
-static inline int uv_apicid_to_nasid(int apicid)
+static inline int uv_apicid_to_pnode(int apicid)
 {
-       return (UV_NASID(apicid >> UV_APIC_NASID_SHIFT));
+       return (apicid >> UV_APIC_PNODE_SHIFT);
 }
 
 /*
  * Access global MMRs using the low memory MMR32 space. This region supports
  * faster MMR access but not all MMRs are accessible in this space.
  */
-static inline unsigned long *uv_global_mmr32_address(int nasid,
+static inline unsigned long *uv_global_mmr32_address(int pnode,
                                unsigned long offset)
 {
        return __va(UV_GLOBAL_MMR32_BASE |
-                      UV_GLOBAL_MMR32_NASID_BITS(nasid) | offset);
+                      UV_GLOBAL_MMR32_PNODE_BITS(pnode) | offset);
 }
 
-static inline void uv_write_global_mmr32(int nasid, unsigned long offset,
+static inline void uv_write_global_mmr32(int pnode, unsigned long offset,
                                 unsigned long val)
 {
-       *uv_global_mmr32_address(nasid, offset) = val;
+       *uv_global_mmr32_address(pnode, offset) = val;
 }
 
-static inline unsigned long uv_read_global_mmr32(int nasid,
+static inline unsigned long uv_read_global_mmr32(int pnode,
                                                 unsigned long offset)
 {
-       return *uv_global_mmr32_address(nasid, offset);
+       return *uv_global_mmr32_address(pnode, offset);
 }
 
 /*
  * Access Global MMR space using the MMR space located at the top of physical
  * memory.
  */
-static inline unsigned long *uv_global_mmr64_address(int nasid,
+static inline unsigned long *uv_global_mmr64_address(int pnode,
                                unsigned long offset)
 {
        return __va(UV_GLOBAL_MMR64_BASE |
-                      UV_GLOBAL_MMR64_NASID_BITS(nasid) | offset);
+                   UV_GLOBAL_MMR64_PNODE_BITS(pnode) | offset);
 }
 
-static inline void uv_write_global_mmr64(int nasid, unsigned long offset,
+static inline void uv_write_global_mmr64(int pnode, unsigned long offset,
                                unsigned long val)
 {
-       *uv_global_mmr64_address(nasid, offset) = val;
+       *uv_global_mmr64_address(pnode, offset) = val;
 }
 
-static inline unsigned long uv_read_global_mmr64(int nasid,
+static inline unsigned long uv_read_global_mmr64(int pnode,
                                                 unsigned long offset)
 {
-       return *uv_global_mmr64_address(nasid, offset);
+       return *uv_global_mmr64_address(pnode, offset);
 }
 
 /*
- * Access node local MMRs. Faster than using global space but only local MMRs
+ * Access hub local MMRs. Faster than using global space but only local MMRs
  * are accessible.
  */
 static inline unsigned long *uv_local_mmr_address(unsigned long offset)
@@ -207,15 +277,15 @@ static inline void uv_write_local_mmr(unsigned long offset, unsigned long val)
 }
 
 /*
- * Structures and definitions for converting between cpu, node, and blade
+ * Structures and definitions for converting between cpu, node, pnode, and blade
  * numbers.
  */
 struct uv_blade_info {
-       unsigned short  nr_posible_cpus;
+       unsigned short  nr_possible_cpus;
        unsigned short  nr_online_cpus;
-       unsigned short  nasid;
+       unsigned short  pnode;
 };
-struct uv_blade_info *uv_blade_info;
+extern struct uv_blade_info *uv_blade_info;
 extern short *uv_node_to_blade;
 extern short *uv_cpu_to_blade;
 extern short uv_possible_blades;
@@ -244,16 +314,16 @@ static inline int uv_node_to_blade_id(int nid)
        return uv_node_to_blade[nid];
 }
 
-/* Convert a blade id to the NASID of the blade */
-static inline int uv_blade_to_nasid(int bid)
+/* Convert a blade id to the PNODE of the blade */
+static inline int uv_blade_to_pnode(int bid)
 {
-       return uv_blade_info[bid].nasid;
+       return uv_blade_info[bid].pnode;
 }
 
 /* Determine the number of possible cpus on a blade */
 static inline int uv_blade_nr_possible_cpus(int bid)
 {
-       return uv_blade_info[bid].nr_posible_cpus;
+       return uv_blade_info[bid].nr_possible_cpus;
 }
 
 /* Determine the number of online cpus on a blade */
@@ -262,16 +332,16 @@ static inline int uv_blade_nr_online_cpus(int bid)
        return uv_blade_info[bid].nr_online_cpus;
 }
 
-/* Convert a cpu id to the NASID of the blade containing the cpu */
-static inline int uv_cpu_to_nasid(int cpu)
+/* Convert a cpu id to the PNODE of the blade containing the cpu */
+static inline int uv_cpu_to_pnode(int cpu)
 {
-       return uv_blade_info[uv_cpu_to_blade_id(cpu)].nasid;
+       return uv_blade_info[uv_cpu_to_blade_id(cpu)].pnode;
 }
 
-/* Convert a node number to the NASID of the blade */
-static inline int uv_node_to_nasid(int nid)
+/* Convert a linux node number to the PNODE of the blade */
+static inline int uv_node_to_pnode(int nid)
 {
-       return uv_blade_info[uv_node_to_blade_id(nid)].nasid;
+       return uv_blade_info[uv_node_to_blade_id(nid)].pnode;
 }
 
 /* Maximum possible number of blades */
index 3b69fe6b6376d28c24b7feacaac054fb298c61fb..151fd7fcb809138d3454c50f023de8b1b49d5335 100644 (file)
 #ifndef __ASM_X86_UV_MMRS__
 #define __ASM_X86_UV_MMRS__
 
-/*
- *       AUTO GENERATED - Do not edit
- */
+#define UV_MMR_ENABLE          (1UL << 63)
+
+/* ========================================================================= */
+/*                           UVH_BAU_DATA_CONFIG                             */
+/* ========================================================================= */
+#define UVH_BAU_DATA_CONFIG 0x61680UL
+#define UVH_BAU_DATA_CONFIG_32 0x0438
+
+#define UVH_BAU_DATA_CONFIG_VECTOR_SHFT 0
+#define UVH_BAU_DATA_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_BAU_DATA_CONFIG_DM_SHFT 8
+#define UVH_BAU_DATA_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_BAU_DATA_CONFIG_DESTMODE_SHFT 11
+#define UVH_BAU_DATA_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_BAU_DATA_CONFIG_STATUS_SHFT 12
+#define UVH_BAU_DATA_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_BAU_DATA_CONFIG_P_SHFT 13
+#define UVH_BAU_DATA_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_BAU_DATA_CONFIG_T_SHFT 15
+#define UVH_BAU_DATA_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_BAU_DATA_CONFIG_M_SHFT 16
+#define UVH_BAU_DATA_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_BAU_DATA_CONFIG_APIC_ID_SHFT 32
+#define UVH_BAU_DATA_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_bau_data_config_u {
+    unsigned long      v;
+    struct uvh_bau_data_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                           UVH_EVENT_OCCURRED0                             */
+/* ========================================================================= */
+#define UVH_EVENT_OCCURRED0 0x70000UL
+#define UVH_EVENT_OCCURRED0_32 0x005e8
+
+#define UVH_EVENT_OCCURRED0_LB_HCERR_SHFT 0
+#define UVH_EVENT_OCCURRED0_LB_HCERR_MASK 0x0000000000000001UL
+#define UVH_EVENT_OCCURRED0_GR0_HCERR_SHFT 1
+#define UVH_EVENT_OCCURRED0_GR0_HCERR_MASK 0x0000000000000002UL
+#define UVH_EVENT_OCCURRED0_GR1_HCERR_SHFT 2
+#define UVH_EVENT_OCCURRED0_GR1_HCERR_MASK 0x0000000000000004UL
+#define UVH_EVENT_OCCURRED0_LH_HCERR_SHFT 3
+#define UVH_EVENT_OCCURRED0_LH_HCERR_MASK 0x0000000000000008UL
+#define UVH_EVENT_OCCURRED0_RH_HCERR_SHFT 4
+#define UVH_EVENT_OCCURRED0_RH_HCERR_MASK 0x0000000000000010UL
+#define UVH_EVENT_OCCURRED0_XN_HCERR_SHFT 5
+#define UVH_EVENT_OCCURRED0_XN_HCERR_MASK 0x0000000000000020UL
+#define UVH_EVENT_OCCURRED0_SI_HCERR_SHFT 6
+#define UVH_EVENT_OCCURRED0_SI_HCERR_MASK 0x0000000000000040UL
+#define UVH_EVENT_OCCURRED0_LB_AOERR0_SHFT 7
+#define UVH_EVENT_OCCURRED0_LB_AOERR0_MASK 0x0000000000000080UL
+#define UVH_EVENT_OCCURRED0_GR0_AOERR0_SHFT 8
+#define UVH_EVENT_OCCURRED0_GR0_AOERR0_MASK 0x0000000000000100UL
+#define UVH_EVENT_OCCURRED0_GR1_AOERR0_SHFT 9
+#define UVH_EVENT_OCCURRED0_GR1_AOERR0_MASK 0x0000000000000200UL
+#define UVH_EVENT_OCCURRED0_LH_AOERR0_SHFT 10
+#define UVH_EVENT_OCCURRED0_LH_AOERR0_MASK 0x0000000000000400UL
+#define UVH_EVENT_OCCURRED0_RH_AOERR0_SHFT 11
+#define UVH_EVENT_OCCURRED0_RH_AOERR0_MASK 0x0000000000000800UL
+#define UVH_EVENT_OCCURRED0_XN_AOERR0_SHFT 12
+#define UVH_EVENT_OCCURRED0_XN_AOERR0_MASK 0x0000000000001000UL
+#define UVH_EVENT_OCCURRED0_SI_AOERR0_SHFT 13
+#define UVH_EVENT_OCCURRED0_SI_AOERR0_MASK 0x0000000000002000UL
+#define UVH_EVENT_OCCURRED0_LB_AOERR1_SHFT 14
+#define UVH_EVENT_OCCURRED0_LB_AOERR1_MASK 0x0000000000004000UL
+#define UVH_EVENT_OCCURRED0_GR0_AOERR1_SHFT 15
+#define UVH_EVENT_OCCURRED0_GR0_AOERR1_MASK 0x0000000000008000UL
+#define UVH_EVENT_OCCURRED0_GR1_AOERR1_SHFT 16
+#define UVH_EVENT_OCCURRED0_GR1_AOERR1_MASK 0x0000000000010000UL
+#define UVH_EVENT_OCCURRED0_LH_AOERR1_SHFT 17
+#define UVH_EVENT_OCCURRED0_LH_AOERR1_MASK 0x0000000000020000UL
+#define UVH_EVENT_OCCURRED0_RH_AOERR1_SHFT 18
+#define UVH_EVENT_OCCURRED0_RH_AOERR1_MASK 0x0000000000040000UL
+#define UVH_EVENT_OCCURRED0_XN_AOERR1_SHFT 19
+#define UVH_EVENT_OCCURRED0_XN_AOERR1_MASK 0x0000000000080000UL
+#define UVH_EVENT_OCCURRED0_SI_AOERR1_SHFT 20
+#define UVH_EVENT_OCCURRED0_SI_AOERR1_MASK 0x0000000000100000UL
+#define UVH_EVENT_OCCURRED0_RH_VPI_INT_SHFT 21
+#define UVH_EVENT_OCCURRED0_RH_VPI_INT_MASK 0x0000000000200000UL
+#define UVH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT 22
+#define UVH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK 0x0000000000400000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT 23
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK 0x0000000000800000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT 24
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK 0x0000000001000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT 25
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK 0x0000000002000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT 26
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK 0x0000000004000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT 27
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK 0x0000000008000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT 28
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK 0x0000000010000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT 29
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK 0x0000000020000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT 30
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK 0x0000000040000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT 31
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK 0x0000000080000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT 32
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK 0x0000000100000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT 33
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK 0x0000000200000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT 34
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK 0x0000000400000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT 35
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK 0x0000000800000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT 36
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK 0x0000001000000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT 37
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK 0x0000002000000000UL
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT 38
+#define UVH_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK 0x0000004000000000UL
+#define UVH_EVENT_OCCURRED0_L1_NMI_INT_SHFT 39
+#define UVH_EVENT_OCCURRED0_L1_NMI_INT_MASK 0x0000008000000000UL
+#define UVH_EVENT_OCCURRED0_STOP_CLOCK_SHFT 40
+#define UVH_EVENT_OCCURRED0_STOP_CLOCK_MASK 0x0000010000000000UL
+#define UVH_EVENT_OCCURRED0_ASIC_TO_L1_SHFT 41
+#define UVH_EVENT_OCCURRED0_ASIC_TO_L1_MASK 0x0000020000000000UL
+#define UVH_EVENT_OCCURRED0_L1_TO_ASIC_SHFT 42
+#define UVH_EVENT_OCCURRED0_L1_TO_ASIC_MASK 0x0000040000000000UL
+#define UVH_EVENT_OCCURRED0_LTC_INT_SHFT 43
+#define UVH_EVENT_OCCURRED0_LTC_INT_MASK 0x0000080000000000UL
+#define UVH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT 44
+#define UVH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK 0x0000100000000000UL
+#define UVH_EVENT_OCCURRED0_IPI_INT_SHFT 45
+#define UVH_EVENT_OCCURRED0_IPI_INT_MASK 0x0000200000000000UL
+#define UVH_EVENT_OCCURRED0_EXTIO_INT0_SHFT 46
+#define UVH_EVENT_OCCURRED0_EXTIO_INT0_MASK 0x0000400000000000UL
+#define UVH_EVENT_OCCURRED0_EXTIO_INT1_SHFT 47
+#define UVH_EVENT_OCCURRED0_EXTIO_INT1_MASK 0x0000800000000000UL
+#define UVH_EVENT_OCCURRED0_EXTIO_INT2_SHFT 48
+#define UVH_EVENT_OCCURRED0_EXTIO_INT2_MASK 0x0001000000000000UL
+#define UVH_EVENT_OCCURRED0_EXTIO_INT3_SHFT 49
+#define UVH_EVENT_OCCURRED0_EXTIO_INT3_MASK 0x0002000000000000UL
+#define UVH_EVENT_OCCURRED0_PROFILE_INT_SHFT 50
+#define UVH_EVENT_OCCURRED0_PROFILE_INT_MASK 0x0004000000000000UL
+#define UVH_EVENT_OCCURRED0_RTC0_SHFT 51
+#define UVH_EVENT_OCCURRED0_RTC0_MASK 0x0008000000000000UL
+#define UVH_EVENT_OCCURRED0_RTC1_SHFT 52
+#define UVH_EVENT_OCCURRED0_RTC1_MASK 0x0010000000000000UL
+#define UVH_EVENT_OCCURRED0_RTC2_SHFT 53
+#define UVH_EVENT_OCCURRED0_RTC2_MASK 0x0020000000000000UL
+#define UVH_EVENT_OCCURRED0_RTC3_SHFT 54
+#define UVH_EVENT_OCCURRED0_RTC3_MASK 0x0040000000000000UL
+#define UVH_EVENT_OCCURRED0_BAU_DATA_SHFT 55
+#define UVH_EVENT_OCCURRED0_BAU_DATA_MASK 0x0080000000000000UL
+#define UVH_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56
+#define UVH_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL
+union uvh_event_occurred0_u {
+    unsigned long      v;
+    struct uvh_event_occurred0_s {
+       unsigned long   lb_hcerr             :  1;  /* RW, W1C */
+       unsigned long   gr0_hcerr            :  1;  /* RW, W1C */
+       unsigned long   gr1_hcerr            :  1;  /* RW, W1C */
+       unsigned long   lh_hcerr             :  1;  /* RW, W1C */
+       unsigned long   rh_hcerr             :  1;  /* RW, W1C */
+       unsigned long   xn_hcerr             :  1;  /* RW, W1C */
+       unsigned long   si_hcerr             :  1;  /* RW, W1C */
+       unsigned long   lb_aoerr0            :  1;  /* RW, W1C */
+       unsigned long   gr0_aoerr0           :  1;  /* RW, W1C */
+       unsigned long   gr1_aoerr0           :  1;  /* RW, W1C */
+       unsigned long   lh_aoerr0            :  1;  /* RW, W1C */
+       unsigned long   rh_aoerr0            :  1;  /* RW, W1C */
+       unsigned long   xn_aoerr0            :  1;  /* RW, W1C */
+       unsigned long   si_aoerr0            :  1;  /* RW, W1C */
+       unsigned long   lb_aoerr1            :  1;  /* RW, W1C */
+       unsigned long   gr0_aoerr1           :  1;  /* RW, W1C */
+       unsigned long   gr1_aoerr1           :  1;  /* RW, W1C */
+       unsigned long   lh_aoerr1            :  1;  /* RW, W1C */
+       unsigned long   rh_aoerr1            :  1;  /* RW, W1C */
+       unsigned long   xn_aoerr1            :  1;  /* RW, W1C */
+       unsigned long   si_aoerr1            :  1;  /* RW, W1C */
+       unsigned long   rh_vpi_int           :  1;  /* RW, W1C */
+       unsigned long   system_shutdown_int  :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_0         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_1         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_2         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_3         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_4         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_5         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_6         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_7         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_8         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_9         :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_10        :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_11        :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_12        :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_13        :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_14        :  1;  /* RW, W1C */
+       unsigned long   lb_irq_int_15        :  1;  /* RW, W1C */
+       unsigned long   l1_nmi_int           :  1;  /* RW, W1C */
+       unsigned long   stop_clock           :  1;  /* RW, W1C */
+       unsigned long   asic_to_l1           :  1;  /* RW, W1C */
+       unsigned long   l1_to_asic           :  1;  /* RW, W1C */
+       unsigned long   ltc_int              :  1;  /* RW, W1C */
+       unsigned long   la_seq_trigger       :  1;  /* RW, W1C */
+       unsigned long   ipi_int              :  1;  /* RW, W1C */
+       unsigned long   extio_int0           :  1;  /* RW, W1C */
+       unsigned long   extio_int1           :  1;  /* RW, W1C */
+       unsigned long   extio_int2           :  1;  /* RW, W1C */
+       unsigned long   extio_int3           :  1;  /* RW, W1C */
+       unsigned long   profile_int          :  1;  /* RW, W1C */
+       unsigned long   rtc0                 :  1;  /* RW, W1C */
+       unsigned long   rtc1                 :  1;  /* RW, W1C */
+       unsigned long   rtc2                 :  1;  /* RW, W1C */
+       unsigned long   rtc3                 :  1;  /* RW, W1C */
+       unsigned long   bau_data             :  1;  /* RW, W1C */
+       unsigned long   power_management_req :  1;  /* RW, W1C */
+       unsigned long   rsvd_57_63           :  7;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                        UVH_EVENT_OCCURRED0_ALIAS                          */
+/* ========================================================================= */
+#define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL
+#define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0
+
+/* ========================================================================= */
+/*                               UVH_INT_CMPB                                */
+/* ========================================================================= */
+#define UVH_INT_CMPB 0x22080UL
+
+#define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT 0
+#define UVH_INT_CMPB_REAL_TIME_CMPB_MASK 0x00ffffffffffffffUL
+
+union uvh_int_cmpb_u {
+    unsigned long      v;
+    struct uvh_int_cmpb_s {
+       unsigned long   real_time_cmpb : 56;  /* RW */
+       unsigned long   rsvd_56_63     :  8;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                               UVH_INT_CMPC                                */
+/* ========================================================================= */
+#define UVH_INT_CMPC 0x22100UL
+
+#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT 0
+#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK 0x00ffffffffffffffUL
+
+union uvh_int_cmpc_u {
+    unsigned long      v;
+    struct uvh_int_cmpc_s {
+       unsigned long   real_time_cmpc : 56;  /* RW */
+       unsigned long   rsvd_56_63     :  8;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                               UVH_INT_CMPD                                */
+/* ========================================================================= */
+#define UVH_INT_CMPD 0x22180UL
 
- #define UV_MMR_ENABLE         (1UL << 63)
+#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT 0
+#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK 0x00ffffffffffffffUL
+
+union uvh_int_cmpd_u {
+    unsigned long      v;
+    struct uvh_int_cmpd_s {
+       unsigned long   real_time_cmpd : 56;  /* RW */
+       unsigned long   rsvd_56_63     :  8;  /*    */
+    } s;
+};
 
 /* ========================================================================= */
 /*                               UVH_IPI_INT                                 */
 /* ========================================================================= */
 #define UVH_IPI_INT 0x60500UL
-#define UVH_IPI_INT_32 0x0360
+#define UVH_IPI_INT_32 0x0348
 
 #define UVH_IPI_INT_VECTOR_SHFT 0
 #define UVH_IPI_INT_VECTOR_MASK 0x00000000000000ffUL
@@ -51,7 +324,7 @@ union uvh_ipi_int_u {
 /*                   UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST                     */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x009f0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x009c0
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_MASK 0x000007fffffffff0UL
@@ -73,7 +346,7 @@ union uvh_lb_bau_intd_payload_queue_first_u {
 /*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST                     */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x009f8
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x009c8
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK 0x000007fffffffff0UL
@@ -91,7 +364,7 @@ union uvh_lb_bau_intd_payload_queue_last_u {
 /*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL                     */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x00a00
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x009d0
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK 0x000007fffffffff0UL
@@ -109,6 +382,7 @@ union uvh_lb_bau_intd_payload_queue_tail_u {
 /*                   UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE                    */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0x0a68
 
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_MASK 0x0000000000000001UL
@@ -169,12 +443,13 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 /*                UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS                 */
 /* ========================================================================= */
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x0000000000320088UL
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0x0a70
 
 /* ========================================================================= */
 /*                     UVH_LB_BAU_SB_ACTIVATION_CONTROL                      */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x009d8
+#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x009a8
 
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT 0
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_MASK 0x000000000000003fUL
@@ -197,7 +472,7 @@ union uvh_lb_bau_sb_activation_control_u {
 /*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_0                      */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x009e0
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x009b0
 
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT 0
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK 0xffffffffffffffffUL
@@ -213,7 +488,7 @@ union uvh_lb_bau_sb_activation_status_0_u {
 /*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_1                      */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x009e8
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x009b8
 
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT 0
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK 0xffffffffffffffffUL
@@ -229,7 +504,7 @@ union uvh_lb_bau_sb_activation_status_1_u {
 /*                      UVH_LB_BAU_SB_DESCRIPTOR_BASE                        */
 /* ========================================================================= */
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x009d0
+#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x009a0
 
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT 12
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_MASK 0x000007fffffff000UL
@@ -247,6 +522,334 @@ union uvh_lb_bau_sb_descriptor_base_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                      UVH_LB_MCAST_AOERR0_RPT_ENABLE                       */
+/* ========================================================================= */
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE 0x50b20UL
+
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_OBESE_MSG_SHFT 0
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_OBESE_MSG_MASK 0x0000000000000001UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_DATA_SB_ERR_SHFT 1
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_DATA_SB_ERR_MASK 0x0000000000000002UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_NACK_BUFF_PARITY_SHFT 2
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_NACK_BUFF_PARITY_MASK 0x0000000000000004UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_TIMEOUT_SHFT 3
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_TIMEOUT_MASK 0x0000000000000008UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_INACTIVE_REPLY_SHFT 4
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_INACTIVE_REPLY_MASK 0x0000000000000010UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_UPGRADE_ERROR_SHFT 5
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_UPGRADE_ERROR_MASK 0x0000000000000020UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_REG_COUNT_UNDERFLOW_SHFT 6
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_REG_COUNT_UNDERFLOW_MASK 0x0000000000000040UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_REP_OBESE_MSG_SHFT 7
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MCAST_REP_OBESE_MSG_MASK 0x0000000000000080UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REQ_RUNT_MSG_SHFT 8
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REQ_RUNT_MSG_MASK 0x0000000000000100UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REQ_OBESE_MSG_SHFT 9
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REQ_OBESE_MSG_MASK 0x0000000000000200UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REQ_DATA_SB_ERR_SHFT 10
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REQ_DATA_SB_ERR_MASK 0x0000000000000400UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_RUNT_MSG_SHFT 11
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_RUNT_MSG_MASK 0x0000000000000800UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_OBESE_MSG_SHFT 12
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_OBESE_MSG_MASK 0x0000000000001000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_DATA_SB_ERR_SHFT 13
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_DATA_SB_ERR_MASK 0x0000000000002000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_COMMAND_ERR_SHFT 14
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_REP_COMMAND_ERR_MASK 0x0000000000004000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_PEND_TIMEOUT_SHFT 15
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_UCACHE_PEND_TIMEOUT_MASK 0x0000000000008000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REQ_RUNT_MSG_SHFT 16
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REQ_RUNT_MSG_MASK 0x0000000000010000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REQ_OBESE_MSG_SHFT 17
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REQ_OBESE_MSG_MASK 0x0000000000020000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REQ_DATA_SB_ERR_SHFT 18
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REQ_DATA_SB_ERR_MASK 0x0000000000040000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REP_RUNT_MSG_SHFT 19
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REP_RUNT_MSG_MASK 0x0000000000080000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REP_OBESE_MSG_SHFT 20
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REP_OBESE_MSG_MASK 0x0000000000100000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REP_DATA_SB_ERR_SHFT 21
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_REP_DATA_SB_ERR_MASK 0x0000000000200000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_AMO_TIMEOUT_SHFT 22
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_AMO_TIMEOUT_MASK 0x0000000000400000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_PUT_TIMEOUT_SHFT 23
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_PUT_TIMEOUT_MASK 0x0000000000800000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_SPURIOUS_EVENT_SHFT 24
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_MACC_SPURIOUS_EVENT_MASK 0x0000000001000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_IOH_DESTINATION_TABLE_PARITY_SHFT 25
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_IOH_DESTINATION_TABLE_PARITY_MASK 0x0000000002000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_GET_HAD_ERROR_REPLY_SHFT 26
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_GET_HAD_ERROR_REPLY_MASK 0x0000000004000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_GET_TIMEOUT_SHFT 27
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_GET_TIMEOUT_MASK 0x0000000008000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_LOCK_MANAGER_HAD_ERROR_REPLY_SHFT 28
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_LOCK_MANAGER_HAD_ERROR_REPLY_MASK 0x0000000010000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_PUT_HAD_ERROR_REPLY_SHFT 29
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_PUT_HAD_ERROR_REPLY_MASK 0x0000000020000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_PUT_TIMEOUT_SHFT 30
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_PUT_TIMEOUT_MASK 0x0000000040000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_SB_ACTIVATION_OVERRUN_SHFT 31
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_SB_ACTIVATION_OVERRUN_MASK 0x0000000080000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_COMPLETED_GB_ACTIVATION_HAD_ERROR_REPLY_SHFT 32
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_COMPLETED_GB_ACTIVATION_HAD_ERROR_REPLY_MASK 0x0000000100000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_COMPLETED_GB_ACTIVATION_TIMEOUT_SHFT 33
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_COMPLETED_GB_ACTIVATION_TIMEOUT_MASK 0x0000000200000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_DESCRIPTOR_BUFFER_0_PARITY_SHFT 34
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_DESCRIPTOR_BUFFER_0_PARITY_MASK 0x0000000400000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_DESCRIPTOR_BUFFER_1_PARITY_SHFT 35
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_DESCRIPTOR_BUFFER_1_PARITY_MASK 0x0000000800000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_SOCKET_DESTINATION_TABLE_PARITY_SHFT 36
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_SOCKET_DESTINATION_TABLE_PARITY_MASK 0x0000001000000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_BAU_REPLY_PAYLOAD_CORRUPTION_SHFT 37
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_BAU_REPLY_PAYLOAD_CORRUPTION_MASK 0x0000002000000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_IO_PORT_DESTINATION_TABLE_PARITY_SHFT 38
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_IO_PORT_DESTINATION_TABLE_PARITY_MASK 0x0000004000000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INTD_SOFT_ACK_TIMEOUT_SHFT 39
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INTD_SOFT_ACK_TIMEOUT_MASK 0x0000008000000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INT_REP_OBESE_MSG_SHFT 40
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INT_REP_OBESE_MSG_MASK 0x0000010000000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INT_REP_COMMAND_ERR_SHFT 41
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INT_REP_COMMAND_ERR_MASK 0x0000020000000000UL
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INT_TIMEOUT_SHFT 42
+#define UVH_LB_MCAST_AOERR0_RPT_ENABLE_INT_TIMEOUT_MASK 0x0000040000000000UL
+
+union uvh_lb_mcast_aoerr0_rpt_enable_u {
+    unsigned long      v;
+    struct uvh_lb_mcast_aoerr0_rpt_enable_s {
+       unsigned long   mcast_obese_msg                         :  1;  /* RW */
+       unsigned long   mcast_data_sb_err                       :  1;  /* RW */
+       unsigned long   mcast_nack_buff_parity                  :  1;  /* RW */
+       unsigned long   mcast_timeout                           :  1;  /* RW */
+       unsigned long   mcast_inactive_reply                    :  1;  /* RW */
+       unsigned long   mcast_upgrade_error                     :  1;  /* RW */
+       unsigned long   mcast_reg_count_underflow               :  1;  /* RW */
+       unsigned long   mcast_rep_obese_msg                     :  1;  /* RW */
+       unsigned long   ucache_req_runt_msg                     :  1;  /* RW */
+       unsigned long   ucache_req_obese_msg                    :  1;  /* RW */
+       unsigned long   ucache_req_data_sb_err                  :  1;  /* RW */
+       unsigned long   ucache_rep_runt_msg                     :  1;  /* RW */
+       unsigned long   ucache_rep_obese_msg                    :  1;  /* RW */
+       unsigned long   ucache_rep_data_sb_err                  :  1;  /* RW */
+       unsigned long   ucache_rep_command_err                  :  1;  /* RW */
+       unsigned long   ucache_pend_timeout                     :  1;  /* RW */
+       unsigned long   macc_req_runt_msg                       :  1;  /* RW */
+       unsigned long   macc_req_obese_msg                      :  1;  /* RW */
+       unsigned long   macc_req_data_sb_err                    :  1;  /* RW */
+       unsigned long   macc_rep_runt_msg                       :  1;  /* RW */
+       unsigned long   macc_rep_obese_msg                      :  1;  /* RW */
+       unsigned long   macc_rep_data_sb_err                    :  1;  /* RW */
+       unsigned long   macc_amo_timeout                        :  1;  /* RW */
+       unsigned long   macc_put_timeout                        :  1;  /* RW */
+       unsigned long   macc_spurious_event                     :  1;  /* RW */
+       unsigned long   ioh_destination_table_parity            :  1;  /* RW */
+       unsigned long   get_had_error_reply                     :  1;  /* RW */
+       unsigned long   get_timeout                             :  1;  /* RW */
+       unsigned long   lock_manager_had_error_reply            :  1;  /* RW */
+       unsigned long   put_had_error_reply                     :  1;  /* RW */
+       unsigned long   put_timeout                             :  1;  /* RW */
+       unsigned long   sb_activation_overrun                   :  1;  /* RW */
+       unsigned long   completed_gb_activation_had_error_reply :  1;  /* RW */
+       unsigned long   completed_gb_activation_timeout         :  1;  /* RW */
+       unsigned long   descriptor_buffer_0_parity              :  1;  /* RW */
+       unsigned long   descriptor_buffer_1_parity              :  1;  /* RW */
+       unsigned long   socket_destination_table_parity         :  1;  /* RW */
+       unsigned long   bau_reply_payload_corruption            :  1;  /* RW */
+       unsigned long   io_port_destination_table_parity        :  1;  /* RW */
+       unsigned long   intd_soft_ack_timeout                   :  1;  /* RW */
+       unsigned long   int_rep_obese_msg                       :  1;  /* RW */
+       unsigned long   int_rep_command_err                     :  1;  /* RW */
+       unsigned long   int_timeout                             :  1;  /* RW */
+       unsigned long   rsvd_43_63                              : 21;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                          UVH_LOCAL_INT0_CONFIG                            */
+/* ========================================================================= */
+#define UVH_LOCAL_INT0_CONFIG 0x61000UL
+
+#define UVH_LOCAL_INT0_CONFIG_VECTOR_SHFT 0
+#define UVH_LOCAL_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_LOCAL_INT0_CONFIG_DM_SHFT 8
+#define UVH_LOCAL_INT0_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_LOCAL_INT0_CONFIG_DESTMODE_SHFT 11
+#define UVH_LOCAL_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_LOCAL_INT0_CONFIG_STATUS_SHFT 12
+#define UVH_LOCAL_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_LOCAL_INT0_CONFIG_P_SHFT 13
+#define UVH_LOCAL_INT0_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_LOCAL_INT0_CONFIG_T_SHFT 15
+#define UVH_LOCAL_INT0_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_LOCAL_INT0_CONFIG_M_SHFT 16
+#define UVH_LOCAL_INT0_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_LOCAL_INT0_CONFIG_APIC_ID_SHFT 32
+#define UVH_LOCAL_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_local_int0_config_u {
+    unsigned long      v;
+    struct uvh_local_int0_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                          UVH_LOCAL_INT0_ENABLE                            */
+/* ========================================================================= */
+#define UVH_LOCAL_INT0_ENABLE 0x65000UL
+
+#define UVH_LOCAL_INT0_ENABLE_LB_HCERR_SHFT 0
+#define UVH_LOCAL_INT0_ENABLE_LB_HCERR_MASK 0x0000000000000001UL
+#define UVH_LOCAL_INT0_ENABLE_GR0_HCERR_SHFT 1
+#define UVH_LOCAL_INT0_ENABLE_GR0_HCERR_MASK 0x0000000000000002UL
+#define UVH_LOCAL_INT0_ENABLE_GR1_HCERR_SHFT 2
+#define UVH_LOCAL_INT0_ENABLE_GR1_HCERR_MASK 0x0000000000000004UL
+#define UVH_LOCAL_INT0_ENABLE_LH_HCERR_SHFT 3
+#define UVH_LOCAL_INT0_ENABLE_LH_HCERR_MASK 0x0000000000000008UL
+#define UVH_LOCAL_INT0_ENABLE_RH_HCERR_SHFT 4
+#define UVH_LOCAL_INT0_ENABLE_RH_HCERR_MASK 0x0000000000000010UL
+#define UVH_LOCAL_INT0_ENABLE_XN_HCERR_SHFT 5
+#define UVH_LOCAL_INT0_ENABLE_XN_HCERR_MASK 0x0000000000000020UL
+#define UVH_LOCAL_INT0_ENABLE_SI_HCERR_SHFT 6
+#define UVH_LOCAL_INT0_ENABLE_SI_HCERR_MASK 0x0000000000000040UL
+#define UVH_LOCAL_INT0_ENABLE_LB_AOERR0_SHFT 7
+#define UVH_LOCAL_INT0_ENABLE_LB_AOERR0_MASK 0x0000000000000080UL
+#define UVH_LOCAL_INT0_ENABLE_GR0_AOERR0_SHFT 8
+#define UVH_LOCAL_INT0_ENABLE_GR0_AOERR0_MASK 0x0000000000000100UL
+#define UVH_LOCAL_INT0_ENABLE_GR1_AOERR0_SHFT 9
+#define UVH_LOCAL_INT0_ENABLE_GR1_AOERR0_MASK 0x0000000000000200UL
+#define UVH_LOCAL_INT0_ENABLE_LH_AOERR0_SHFT 10
+#define UVH_LOCAL_INT0_ENABLE_LH_AOERR0_MASK 0x0000000000000400UL
+#define UVH_LOCAL_INT0_ENABLE_RH_AOERR0_SHFT 11
+#define UVH_LOCAL_INT0_ENABLE_RH_AOERR0_MASK 0x0000000000000800UL
+#define UVH_LOCAL_INT0_ENABLE_XN_AOERR0_SHFT 12
+#define UVH_LOCAL_INT0_ENABLE_XN_AOERR0_MASK 0x0000000000001000UL
+#define UVH_LOCAL_INT0_ENABLE_SI_AOERR0_SHFT 13
+#define UVH_LOCAL_INT0_ENABLE_SI_AOERR0_MASK 0x0000000000002000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_AOERR1_SHFT 14
+#define UVH_LOCAL_INT0_ENABLE_LB_AOERR1_MASK 0x0000000000004000UL
+#define UVH_LOCAL_INT0_ENABLE_GR0_AOERR1_SHFT 15
+#define UVH_LOCAL_INT0_ENABLE_GR0_AOERR1_MASK 0x0000000000008000UL
+#define UVH_LOCAL_INT0_ENABLE_GR1_AOERR1_SHFT 16
+#define UVH_LOCAL_INT0_ENABLE_GR1_AOERR1_MASK 0x0000000000010000UL
+#define UVH_LOCAL_INT0_ENABLE_LH_AOERR1_SHFT 17
+#define UVH_LOCAL_INT0_ENABLE_LH_AOERR1_MASK 0x0000000000020000UL
+#define UVH_LOCAL_INT0_ENABLE_RH_AOERR1_SHFT 18
+#define UVH_LOCAL_INT0_ENABLE_RH_AOERR1_MASK 0x0000000000040000UL
+#define UVH_LOCAL_INT0_ENABLE_XN_AOERR1_SHFT 19
+#define UVH_LOCAL_INT0_ENABLE_XN_AOERR1_MASK 0x0000000000080000UL
+#define UVH_LOCAL_INT0_ENABLE_SI_AOERR1_SHFT 20
+#define UVH_LOCAL_INT0_ENABLE_SI_AOERR1_MASK 0x0000000000100000UL
+#define UVH_LOCAL_INT0_ENABLE_RH_VPI_INT_SHFT 21
+#define UVH_LOCAL_INT0_ENABLE_RH_VPI_INT_MASK 0x0000000000200000UL
+#define UVH_LOCAL_INT0_ENABLE_SYSTEM_SHUTDOWN_INT_SHFT 22
+#define UVH_LOCAL_INT0_ENABLE_SYSTEM_SHUTDOWN_INT_MASK 0x0000000000400000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_0_SHFT 23
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_0_MASK 0x0000000000800000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_1_SHFT 24
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_1_MASK 0x0000000001000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_2_SHFT 25
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_2_MASK 0x0000000002000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_3_SHFT 26
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_3_MASK 0x0000000004000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_4_SHFT 27
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_4_MASK 0x0000000008000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_5_SHFT 28
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_5_MASK 0x0000000010000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_6_SHFT 29
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_6_MASK 0x0000000020000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_7_SHFT 30
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_7_MASK 0x0000000040000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_8_SHFT 31
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_8_MASK 0x0000000080000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_9_SHFT 32
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_9_MASK 0x0000000100000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_10_SHFT 33
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_10_MASK 0x0000000200000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_11_SHFT 34
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_11_MASK 0x0000000400000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_12_SHFT 35
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_12_MASK 0x0000000800000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_13_SHFT 36
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_13_MASK 0x0000001000000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_14_SHFT 37
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_14_MASK 0x0000002000000000UL
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_15_SHFT 38
+#define UVH_LOCAL_INT0_ENABLE_LB_IRQ_INT_15_MASK 0x0000004000000000UL
+#define UVH_LOCAL_INT0_ENABLE_L1_NMI_INT_SHFT 39
+#define UVH_LOCAL_INT0_ENABLE_L1_NMI_INT_MASK 0x0000008000000000UL
+#define UVH_LOCAL_INT0_ENABLE_STOP_CLOCK_SHFT 40
+#define UVH_LOCAL_INT0_ENABLE_STOP_CLOCK_MASK 0x0000010000000000UL
+#define UVH_LOCAL_INT0_ENABLE_ASIC_TO_L1_SHFT 41
+#define UVH_LOCAL_INT0_ENABLE_ASIC_TO_L1_MASK 0x0000020000000000UL
+#define UVH_LOCAL_INT0_ENABLE_L1_TO_ASIC_SHFT 42
+#define UVH_LOCAL_INT0_ENABLE_L1_TO_ASIC_MASK 0x0000040000000000UL
+#define UVH_LOCAL_INT0_ENABLE_LTC_INT_SHFT 43
+#define UVH_LOCAL_INT0_ENABLE_LTC_INT_MASK 0x0000080000000000UL
+#define UVH_LOCAL_INT0_ENABLE_LA_SEQ_TRIGGER_SHFT 44
+#define UVH_LOCAL_INT0_ENABLE_LA_SEQ_TRIGGER_MASK 0x0000100000000000UL
+
+union uvh_local_int0_enable_u {
+    unsigned long      v;
+    struct uvh_local_int0_enable_s {
+       unsigned long   lb_hcerr            :  1;  /* RW */
+       unsigned long   gr0_hcerr           :  1;  /* RW */
+       unsigned long   gr1_hcerr           :  1;  /* RW */
+       unsigned long   lh_hcerr            :  1;  /* RW */
+       unsigned long   rh_hcerr            :  1;  /* RW */
+       unsigned long   xn_hcerr            :  1;  /* RW */
+       unsigned long   si_hcerr            :  1;  /* RW */
+       unsigned long   lb_aoerr0           :  1;  /* RW */
+       unsigned long   gr0_aoerr0          :  1;  /* RW */
+       unsigned long   gr1_aoerr0          :  1;  /* RW */
+       unsigned long   lh_aoerr0           :  1;  /* RW */
+       unsigned long   rh_aoerr0           :  1;  /* RW */
+       unsigned long   xn_aoerr0           :  1;  /* RW */
+       unsigned long   si_aoerr0           :  1;  /* RW */
+       unsigned long   lb_aoerr1           :  1;  /* RW */
+       unsigned long   gr0_aoerr1          :  1;  /* RW */
+       unsigned long   gr1_aoerr1          :  1;  /* RW */
+       unsigned long   lh_aoerr1           :  1;  /* RW */
+       unsigned long   rh_aoerr1           :  1;  /* RW */
+       unsigned long   xn_aoerr1           :  1;  /* RW */
+       unsigned long   si_aoerr1           :  1;  /* RW */
+       unsigned long   rh_vpi_int          :  1;  /* RW */
+       unsigned long   system_shutdown_int :  1;  /* RW */
+       unsigned long   lb_irq_int_0        :  1;  /* RW */
+       unsigned long   lb_irq_int_1        :  1;  /* RW */
+       unsigned long   lb_irq_int_2        :  1;  /* RW */
+       unsigned long   lb_irq_int_3        :  1;  /* RW */
+       unsigned long   lb_irq_int_4        :  1;  /* RW */
+       unsigned long   lb_irq_int_5        :  1;  /* RW */
+       unsigned long   lb_irq_int_6        :  1;  /* RW */
+       unsigned long   lb_irq_int_7        :  1;  /* RW */
+       unsigned long   lb_irq_int_8        :  1;  /* RW */
+       unsigned long   lb_irq_int_9        :  1;  /* RW */
+       unsigned long   lb_irq_int_10       :  1;  /* RW */
+       unsigned long   lb_irq_int_11       :  1;  /* RW */
+       unsigned long   lb_irq_int_12       :  1;  /* RW */
+       unsigned long   lb_irq_int_13       :  1;  /* RW */
+       unsigned long   lb_irq_int_14       :  1;  /* RW */
+       unsigned long   lb_irq_int_15       :  1;  /* RW */
+       unsigned long   l1_nmi_int          :  1;  /* RW */
+       unsigned long   stop_clock          :  1;  /* RW */
+       unsigned long   asic_to_l1          :  1;  /* RW */
+       unsigned long   l1_to_asic          :  1;  /* RW */
+       unsigned long   ltc_int             :  1;  /* RW */
+       unsigned long   la_seq_trigger      :  1;  /* RW */
+       unsigned long   rsvd_45_63          : 19;  /*    */
+    } s;
+};
+
 /* ========================================================================= */
 /*                               UVH_NODE_ID                                 */
 /* ========================================================================= */
@@ -283,6 +886,93 @@ union uvh_node_id_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                          UVH_NODE_PRESENT_TABLE                           */
+/* ========================================================================= */
+#define UVH_NODE_PRESENT_TABLE 0x1400UL
+#define UVH_NODE_PRESENT_TABLE_DEPTH 16
+
+#define UVH_NODE_PRESENT_TABLE_NODES_SHFT 0
+#define UVH_NODE_PRESENT_TABLE_NODES_MASK 0xffffffffffffffffUL
+
+union uvh_node_present_table_u {
+    unsigned long      v;
+    struct uvh_node_present_table_s {
+       unsigned long   nodes : 64;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
+
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+
+union uvh_rh_gam_alias210_redirect_config_0_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_alias210_redirect_config_0_mmr_s {
+       unsigned long   rsvd_0_23 : 24;  /*    */
+       unsigned long   dest_base : 22;  /* RW */
+       unsigned long   rsvd_46_63: 18;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL
+
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+
+union uvh_rh_gam_alias210_redirect_config_1_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_alias210_redirect_config_1_mmr_s {
+       unsigned long   rsvd_0_23 : 24;  /*    */
+       unsigned long   dest_base : 22;  /* RW */
+       unsigned long   rsvd_46_63: 18;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL
+
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
+
+union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_alias210_redirect_config_2_mmr_s {
+       unsigned long   rsvd_0_23 : 24;  /*    */
+       unsigned long   dest_base : 22;  /* RW */
+       unsigned long   rsvd_46_63: 18;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
+/*                    UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR                      */
+/* ========================================================================= */
+#define UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR 0x1600020UL
+
+#define UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_BASE_SHFT 26
+#define UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffffc000000UL
+#define UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_cfg_overlay_config_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_cfg_overlay_config_mmr_s {
+       unsigned long   rsvd_0_25: 26;  /*    */
+       unsigned long   base   : 20;  /* RW */
+       unsigned long   rsvd_46_62: 17;  /*    */
+       unsigned long   enable :  1;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                    UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR                      */
 /* ========================================================================= */
@@ -290,8 +980,8 @@ union uvh_node_id_u {
 
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT 28
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003ffff0000000UL
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 46
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_MASK 0x0000400000000000UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT 48
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_MASK 0x0001000000000000UL
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT 52
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK 0x00f0000000000000UL
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
@@ -302,14 +992,41 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
     struct uvh_rh_gam_gru_overlay_config_mmr_s {
        unsigned long   rsvd_0_27: 28;  /*    */
        unsigned long   base   : 18;  /* RW */
+       unsigned long   rsvd_46_47:  2;  /*    */
        unsigned long   gr4    :  1;  /* RW */
-       unsigned long   rsvd_47_51:  5;  /*    */
+       unsigned long   rsvd_49_51:  3;  /*    */
        unsigned long   n_gru  :  4;  /* RW */
        unsigned long   rsvd_56_62:  7;  /*    */
        unsigned long   enable :  1;  /* RW */
     } s;
 };
 
+/* ========================================================================= */
+/*                   UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR                     */
+/* ========================================================================= */
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
+
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_MASK 0x00003fffc0000000UL
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_MASK 0x000fc00000000000UL
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_SHFT 52
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_N_IO_MASK 0x00f0000000000000UL
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_mmioh_overlay_config_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_mmioh_overlay_config_mmr_s {
+       unsigned long   rsvd_0_29: 30;  /*    */
+       unsigned long   base   : 16;  /* RW */
+       unsigned long   m_io   :  6;  /* RW */
+       unsigned long   n_io   :  4;  /* RW */
+       unsigned long   rsvd_56_62:  7;  /*    */
+       unsigned long   enable :  1;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                    UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR                      */
 /* ========================================================================= */
@@ -336,7 +1053,7 @@ union uvh_rh_gam_mmr_overlay_config_mmr_u {
 /* ========================================================================= */
 /*                                 UVH_RTC                                   */
 /* ========================================================================= */
-#define UVH_RTC 0x28000UL
+#define UVH_RTC 0x340000UL
 
 #define UVH_RTC_REAL_TIME_CLOCK_SHFT 0
 #define UVH_RTC_REAL_TIME_CLOCK_MASK 0x00ffffffffffffffUL
@@ -349,6 +1066,139 @@ union uvh_rtc_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                           UVH_RTC1_INT_CONFIG                             */
+/* ========================================================================= */
+#define UVH_RTC1_INT_CONFIG 0x615c0UL
+
+#define UVH_RTC1_INT_CONFIG_VECTOR_SHFT 0
+#define UVH_RTC1_INT_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_RTC1_INT_CONFIG_DM_SHFT 8
+#define UVH_RTC1_INT_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_RTC1_INT_CONFIG_DESTMODE_SHFT 11
+#define UVH_RTC1_INT_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_RTC1_INT_CONFIG_STATUS_SHFT 12
+#define UVH_RTC1_INT_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_RTC1_INT_CONFIG_P_SHFT 13
+#define UVH_RTC1_INT_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_RTC1_INT_CONFIG_T_SHFT 15
+#define UVH_RTC1_INT_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_RTC1_INT_CONFIG_M_SHFT 16
+#define UVH_RTC1_INT_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_RTC1_INT_CONFIG_APIC_ID_SHFT 32
+#define UVH_RTC1_INT_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_rtc1_int_config_u {
+    unsigned long      v;
+    struct uvh_rtc1_int_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                           UVH_RTC2_INT_CONFIG                             */
+/* ========================================================================= */
+#define UVH_RTC2_INT_CONFIG 0x61600UL
+
+#define UVH_RTC2_INT_CONFIG_VECTOR_SHFT 0
+#define UVH_RTC2_INT_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_RTC2_INT_CONFIG_DM_SHFT 8
+#define UVH_RTC2_INT_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_RTC2_INT_CONFIG_DESTMODE_SHFT 11
+#define UVH_RTC2_INT_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_RTC2_INT_CONFIG_STATUS_SHFT 12
+#define UVH_RTC2_INT_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_RTC2_INT_CONFIG_P_SHFT 13
+#define UVH_RTC2_INT_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_RTC2_INT_CONFIG_T_SHFT 15
+#define UVH_RTC2_INT_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_RTC2_INT_CONFIG_M_SHFT 16
+#define UVH_RTC2_INT_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_RTC2_INT_CONFIG_APIC_ID_SHFT 32
+#define UVH_RTC2_INT_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_rtc2_int_config_u {
+    unsigned long      v;
+    struct uvh_rtc2_int_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                           UVH_RTC3_INT_CONFIG                             */
+/* ========================================================================= */
+#define UVH_RTC3_INT_CONFIG 0x61640UL
+
+#define UVH_RTC3_INT_CONFIG_VECTOR_SHFT 0
+#define UVH_RTC3_INT_CONFIG_VECTOR_MASK 0x00000000000000ffUL
+#define UVH_RTC3_INT_CONFIG_DM_SHFT 8
+#define UVH_RTC3_INT_CONFIG_DM_MASK 0x0000000000000700UL
+#define UVH_RTC3_INT_CONFIG_DESTMODE_SHFT 11
+#define UVH_RTC3_INT_CONFIG_DESTMODE_MASK 0x0000000000000800UL
+#define UVH_RTC3_INT_CONFIG_STATUS_SHFT 12
+#define UVH_RTC3_INT_CONFIG_STATUS_MASK 0x0000000000001000UL
+#define UVH_RTC3_INT_CONFIG_P_SHFT 13
+#define UVH_RTC3_INT_CONFIG_P_MASK 0x0000000000002000UL
+#define UVH_RTC3_INT_CONFIG_T_SHFT 15
+#define UVH_RTC3_INT_CONFIG_T_MASK 0x0000000000008000UL
+#define UVH_RTC3_INT_CONFIG_M_SHFT 16
+#define UVH_RTC3_INT_CONFIG_M_MASK 0x0000000000010000UL
+#define UVH_RTC3_INT_CONFIG_APIC_ID_SHFT 32
+#define UVH_RTC3_INT_CONFIG_APIC_ID_MASK 0xffffffff00000000UL
+
+union uvh_rtc3_int_config_u {
+    unsigned long      v;
+    struct uvh_rtc3_int_config_s {
+       unsigned long   vector_  :  8;  /* RW */
+       unsigned long   dm       :  3;  /* RW */
+       unsigned long   destmode :  1;  /* RW */
+       unsigned long   status   :  1;  /* RO */
+       unsigned long   p        :  1;  /* RO */
+       unsigned long   rsvd_14  :  1;  /*    */
+       unsigned long   t        :  1;  /* RO */
+       unsigned long   m        :  1;  /* RW */
+       unsigned long   rsvd_17_31: 15;  /*    */
+       unsigned long   apic_id  : 32;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                            UVH_RTC_INC_RATIO                              */
+/* ========================================================================= */
+#define UVH_RTC_INC_RATIO 0x350000UL
+
+#define UVH_RTC_INC_RATIO_FRACTION_SHFT 0
+#define UVH_RTC_INC_RATIO_FRACTION_MASK 0x00000000000fffffUL
+#define UVH_RTC_INC_RATIO_RATIO_SHFT 20
+#define UVH_RTC_INC_RATIO_RATIO_MASK 0x0000000000700000UL
+
+union uvh_rtc_inc_ratio_u {
+    unsigned long      v;
+    struct uvh_rtc_inc_ratio_s {
+       unsigned long   fraction : 20;  /* RW */
+       unsigned long   ratio    :  3;  /* RW */
+       unsigned long   rsvd_23_63: 41;  /*    */
+    } s;
+};
+
 /* ========================================================================= */
 /*                          UVH_SI_ADDR_MAP_CONFIG                           */
 /* ========================================================================= */
@@ -369,5 +1219,77 @@ union uvh_si_addr_map_config_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                       UVH_SI_ALIAS0_OVERLAY_CONFIG                        */
+/* ========================================================================= */
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG 0xc80008UL
+
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG_BASE_SHFT 24
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG_M_ALIAS_SHFT 48
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG_ENABLE_SHFT 63
+#define UVH_SI_ALIAS0_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_si_alias0_overlay_config_u {
+    unsigned long      v;
+    struct uvh_si_alias0_overlay_config_s {
+       unsigned long   rsvd_0_23: 24;  /*    */
+       unsigned long   base    :  8;  /* RW */
+       unsigned long   rsvd_32_47: 16;  /*    */
+       unsigned long   m_alias :  5;  /* RW */
+       unsigned long   rsvd_53_62: 10;  /*    */
+       unsigned long   enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                       UVH_SI_ALIAS1_OVERLAY_CONFIG                        */
+/* ========================================================================= */
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG 0xc80010UL
+
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG_BASE_SHFT 24
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG_M_ALIAS_SHFT 48
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG_ENABLE_SHFT 63
+#define UVH_SI_ALIAS1_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_si_alias1_overlay_config_u {
+    unsigned long      v;
+    struct uvh_si_alias1_overlay_config_s {
+       unsigned long   rsvd_0_23: 24;  /*    */
+       unsigned long   base    :  8;  /* RW */
+       unsigned long   rsvd_32_47: 16;  /*    */
+       unsigned long   m_alias :  5;  /* RW */
+       unsigned long   rsvd_53_62: 10;  /*    */
+       unsigned long   enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                       UVH_SI_ALIAS2_OVERLAY_CONFIG                        */
+/* ========================================================================= */
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG 0xc80018UL
+
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG_BASE_SHFT 24
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG_M_ALIAS_SHFT 48
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG_ENABLE_SHFT 63
+#define UVH_SI_ALIAS2_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_si_alias2_overlay_config_u {
+    unsigned long      v;
+    struct uvh_si_alias2_overlay_config_s {
+       unsigned long   rsvd_0_23: 24;  /*    */
+       unsigned long   base    :  8;  /* RW */
+       unsigned long   rsvd_32_47: 16;  /*    */
+       unsigned long   m_alias :  5;  /* RW */
+       unsigned long   rsvd_53_62: 10;  /*    */
+       unsigned long   enable  :  1;  /* RW */
+    } s;
+};
+
 
 #endif /* __ASM_X86_UV_MMRS__ */
diff --git a/include/asm-x86/visws/sgivw.h b/include/asm-x86/visws/sgivw.h
new file mode 100644 (file)
index 0000000..5fbf63e
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * Frame buffer position and size:
+ */
+extern unsigned long sgivwfb_mem_phys;
+extern unsigned long sgivwfb_mem_size;
index 074b357146dfec048d79518ca8bb1107439127bb..5ce351325e011c72721d1f58c0b6e2d6f16f77e7 100644 (file)
 
 #include <asm/processor-flags.h>
 
-#ifdef CONFIG_VM86
-#define X86_VM_MASK    X86_EFLAGS_VM
-#else
-#define X86_VM_MASK    0 /* No VM86 support */
-#endif
-
 #define BIOSSEG                0x0f000
 
 #define CPU_086                0
@@ -121,7 +115,6 @@ struct vm86plus_info_struct {
        unsigned long is_vm86pus:1;           /* for vm86 internal use */
        unsigned char vm86dbg_intxxtab[32];   /* for debugger */
 };
-
 struct vm86plus_struct {
        struct vm86_regs regs;
        unsigned long flags;
@@ -133,6 +126,9 @@ struct vm86plus_struct {
 };
 
 #ifdef __KERNEL__
+
+#include <asm/ptrace.h>
+
 /*
  * This is the (kernel) stack-layout when we have done a "SAVE_ALL" from vm86
  * mode - the main change is that the old segment descriptors aren't
@@ -141,7 +137,6 @@ struct vm86plus_struct {
  * at the end of the structure. Look at ptrace.h to see the "normal"
  * setup. For user space layout see 'struct vm86_regs' above.
  */
-#include <asm/ptrace.h>
 
 struct kernel_vm86_regs {
 /*
index 4781881303285f73455e64249a2d56a44cea3729..c3118c3851565c9ae7a87e0d98e355fbf3efdc7a 100644 (file)
@@ -50,7 +50,7 @@ extern void __init vmi_time_init(void);
 extern unsigned long vmi_get_wallclock(void);
 extern int vmi_set_wallclock(unsigned long now);
 extern unsigned long long vmi_sched_clock(void);
-extern unsigned long vmi_cpu_khz(void);
+extern unsigned long vmi_tsc_khz(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
 extern void __devinit vmi_time_bsp_init(void);
index c2ccd997ed3537f00ff3ea78195a845d3dd27d0c..2a4f9b41d68499d39004fb238a49a528b1a282be 100644 (file)
@@ -176,9 +176,9 @@ HYPERVISOR_fpu_taskswitch(int set)
 }
 
 static inline int
-HYPERVISOR_sched_op(int cmd, unsigned long arg)
+HYPERVISOR_sched_op(int cmd, void *arg)
 {
-       return _hypercall2(int, sched_op, cmd, arg);
+       return _hypercall2(int, sched_op_new, cmd, arg);
 }
 
 static inline long
@@ -314,6 +314,13 @@ HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
        return _hypercall2(int, nmi_op, op, arg);
 }
 
+static inline void
+MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
+{
+       mcl->op = __HYPERVISOR_fpu_taskswitch;
+       mcl->args[0] = set;
+}
+
 static inline void
 MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
                        pte_t new_val, unsigned long flags)
index e11f24038b1db4ff745442a9c8a6094f0151be0a..377c04591c15e7b7d7a2584a176e6d2cb4d8bb77 100644 (file)
@@ -26,15 +26,20 @@ typedef struct xpaddr {
 #define FOREIGN_FRAME_BIT      (1UL<<31)
 #define FOREIGN_FRAME(m)       ((m) | FOREIGN_FRAME_BIT)
 
-extern unsigned long *phys_to_machine_mapping;
+/* Maximum amount of memory we can handle in a domain in pages */
+#define MAX_DOMAIN_PAGES                                               \
+    ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
+
+
+extern unsigned long get_phys_to_machine(unsigned long pfn);
+extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
 
 static inline unsigned long pfn_to_mfn(unsigned long pfn)
 {
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return pfn;
 
-       return phys_to_machine_mapping[(unsigned int)(pfn)] &
-               ~FOREIGN_FRAME_BIT;
+       return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
 }
 
 static inline int phys_to_machine_mapping_valid(unsigned long pfn)
@@ -42,7 +47,7 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn)
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return 1;
 
-       return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
+       return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY;
 }
 
 static inline unsigned long mfn_to_pfn(unsigned long mfn)
@@ -106,20 +111,12 @@ static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
        unsigned long pfn = mfn_to_pfn(mfn);
        if ((pfn < max_mapnr)
            && !xen_feature(XENFEAT_auto_translated_physmap)
-           && (phys_to_machine_mapping[pfn] != mfn))
+           && (get_phys_to_machine(pfn) != mfn))
                return max_mapnr; /* force !pfn_valid() */
+       /* XXX fixme; not true with sparsemem */
        return pfn;
 }
 
-static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
-{
-       if (xen_feature(XENFEAT_auto_translated_physmap)) {
-               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-               return;
-       }
-       phys_to_machine_mapping[pfn] = mfn;
-}
-
 /* VIRT <-> MACHINE conversion */
 #define virt_to_machine(v)     (phys_to_machine(XPADDR(__pa(v))))
 #define virt_to_mfn(v)         (pfn_to_mfn(PFN_DOWN(__pa(v))))
index 067b5c1835a3a93e738fb28420273debfc88a482..921b458404495b2ace1ee3f201f5040e2179a2ee 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef ASM_X86__XOR_32_H
+#define ASM_X86__XOR_32_H
+
 /*
  * Optimized RAID-5 checksumming functions for MMX and SSE.
  *
@@ -881,3 +884,5 @@ do {                                                        \
    deals with a load to a line that is being prefetched.  */
 #define XOR_SELECT_TEMPLATE(FASTEST)                   \
        (cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
+
+#endif /* ASM_X86__XOR_32_H */
index 24957e39ac8aff0f0e7192d31c4b01abd1d3415d..2d3a18de295b5aa03e82fe209ae6c667f97abfd6 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef ASM_X86__XOR_64_H
+#define ASM_X86__XOR_64_H
+
 /*
  * Optimized RAID-5 checksumming functions for MMX and SSE.
  *
@@ -354,3 +357,5 @@ do {                                                \
    We may also be able to load into the L1 only depending on how the cpu
    deals with a load to a line that is being prefetched.  */
 #define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
+
+#endif /* ASM_X86__XOR_64_H */
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
new file mode 100644 (file)
index 0000000..d12498e
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Hash: Hash algorithms under the crypto API
+ * 
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_HASH_H
+#define _CRYPTO_HASH_H
+
+#include <linux/crypto.h>
+
+struct crypto_ahash {
+       struct crypto_tfm base;
+};
+
+static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm)
+{
+       return (struct crypto_ahash *)tfm;
+}
+
+static inline struct crypto_ahash *crypto_alloc_ahash(const char *alg_name,
+                                                     u32 type, u32 mask)
+{
+       type &= ~CRYPTO_ALG_TYPE_MASK;
+       mask &= ~CRYPTO_ALG_TYPE_MASK;
+       type |= CRYPTO_ALG_TYPE_AHASH;
+       mask |= CRYPTO_ALG_TYPE_AHASH_MASK;
+
+       return __crypto_ahash_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm)
+{
+       return &tfm->base;
+}
+
+static inline void crypto_free_ahash(struct crypto_ahash *tfm)
+{
+       crypto_free_tfm(crypto_ahash_tfm(tfm));
+}
+
+static inline unsigned int crypto_ahash_alignmask(
+       struct crypto_ahash *tfm)
+{
+       return crypto_tfm_alg_alignmask(crypto_ahash_tfm(tfm));
+}
+
+static inline struct ahash_tfm *crypto_ahash_crt(struct crypto_ahash *tfm)
+{
+       return &crypto_ahash_tfm(tfm)->crt_ahash;
+}
+
+static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash *tfm)
+{
+       return crypto_ahash_crt(tfm)->digestsize;
+}
+
+static inline u32 crypto_ahash_get_flags(struct crypto_ahash *tfm)
+{
+       return crypto_tfm_get_flags(crypto_ahash_tfm(tfm));
+}
+
+static inline void crypto_ahash_set_flags(struct crypto_ahash *tfm, u32 flags)
+{
+       crypto_tfm_set_flags(crypto_ahash_tfm(tfm), flags);
+}
+
+static inline void crypto_ahash_clear_flags(struct crypto_ahash *tfm, u32 flags)
+{
+       crypto_tfm_clear_flags(crypto_ahash_tfm(tfm), flags);
+}
+
+static inline struct crypto_ahash *crypto_ahash_reqtfm(
+       struct ahash_request *req)
+{
+       return __crypto_ahash_cast(req->base.tfm);
+}
+
+static inline unsigned int crypto_ahash_reqsize(struct crypto_ahash *tfm)
+{
+       return crypto_ahash_crt(tfm)->reqsize;
+}
+
+static inline int crypto_ahash_setkey(struct crypto_ahash *tfm,
+                                     const u8 *key, unsigned int keylen)
+{
+       struct ahash_tfm *crt = crypto_ahash_crt(tfm);
+
+       return crt->setkey(tfm, key, keylen);
+}
+
+static inline int crypto_ahash_digest(struct ahash_request *req)
+{
+       struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
+       return crt->digest(req);
+}
+
+static inline void ahash_request_set_tfm(struct ahash_request *req,
+                                        struct crypto_ahash *tfm)
+{
+       req->base.tfm = crypto_ahash_tfm(tfm);
+}
+
+static inline struct ahash_request *ahash_request_alloc(
+       struct crypto_ahash *tfm, gfp_t gfp)
+{
+       struct ahash_request *req;
+
+       req = kmalloc(sizeof(struct ahash_request) +
+                     crypto_ahash_reqsize(tfm), gfp);
+
+       if (likely(req))
+               ahash_request_set_tfm(req, tfm);
+
+       return req;
+}
+
+static inline void ahash_request_free(struct ahash_request *req)
+{
+       kfree(req);
+}
+
+static inline struct ahash_request *ahash_request_cast(
+       struct crypto_async_request *req)
+{
+       return container_of(req, struct ahash_request, base);
+}
+
+static inline void ahash_request_set_callback(struct ahash_request *req,
+                                             u32 flags,
+                                             crypto_completion_t complete,
+                                             void *data)
+{
+       req->base.complete = complete;
+       req->base.data = data;
+       req->base.flags = flags;
+}
+
+static inline void ahash_request_set_crypt(struct ahash_request *req,
+                                          struct scatterlist *src, u8 *result,
+                                          unsigned int nbytes)
+{
+       req->src = src;
+       req->nbytes = nbytes;
+       req->result = result;
+}
+
+#endif /* _CRYPTO_HASH_H */
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
new file mode 100644 (file)
index 0000000..917ae57
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Hash algorithms.
+ * 
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#ifndef _CRYPTO_INTERNAL_HASH_H
+#define _CRYPTO_INTERNAL_HASH_H
+
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+
+struct ahash_request;
+struct scatterlist;
+
+struct crypto_hash_walk {
+       char *data;
+
+       unsigned int offset;
+       unsigned int alignmask;
+
+       struct page *pg;
+       unsigned int entrylen;
+
+       unsigned int total;
+       struct scatterlist *sg;
+
+       unsigned int flags;
+};
+
+extern const struct crypto_type crypto_ahash_type;
+
+int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err);
+int crypto_hash_walk_first(struct ahash_request *req,
+                          struct crypto_hash_walk *walk);
+
+static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
+{
+       return crypto_tfm_ctx(&tfm->base);
+}
+
+static inline struct ahash_alg *crypto_ahash_alg(
+       struct crypto_ahash *tfm)
+{
+       return &crypto_ahash_tfm(tfm)->__crt_alg->cra_ahash;
+}
+
+static inline int ahash_enqueue_request(struct crypto_queue *queue,
+                                            struct ahash_request *request)
+{
+       return crypto_enqueue_request(queue, &request->base);
+}
+
+static inline struct ahash_request *ahash_dequeue_request(
+       struct crypto_queue *queue)
+{
+       return ahash_request_cast(crypto_dequeue_request(queue));
+}
+
+static inline void *ahash_request_ctx(struct ahash_request *req)
+{
+       return req->__ctx;
+}
+
+static inline int ahash_tfm_in_queue(struct crypto_queue *queue,
+                                         struct crypto_ahash *tfm)
+{
+       return crypto_tfm_in_queue(queue, crypto_ahash_tfm(tfm));
+}
+
+#endif /* _CRYPTO_INTERNAL_HASH_H */
+
diff --git a/include/drm/Kbuild b/include/drm/Kbuild
new file mode 100644 (file)
index 0000000..82b6983
--- /dev/null
@@ -0,0 +1,10 @@
+unifdef-y += drm.h drm_sarea.h
+unifdef-y += i810_drm.h
+unifdef-y += i830_drm.h
+unifdef-y += i915_drm.h
+unifdef-y += mga_drm.h
+unifdef-y += r128_drm.h
+unifdef-y += radeon_drm.h
+unifdef-y += sis_drm.h
+unifdef-y += savage_drm.h
+unifdef-y += via_drm.h
similarity index 100%
rename from drivers/char/drm/drm.h
rename to include/drm/drm.h
similarity index 100%
rename from drivers/char/drm/drmP.h
rename to include/drm/drmP.h
index 41f7ce7edd7aea559be60998d65e68569d7b8d45..0601075d09a13565d0b1ea94e9d0bba1947e95df 100644 (file)
@@ -82,6 +82,7 @@ char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 int early_acpi_boot_init(void);
 int acpi_boot_init (void);
 int acpi_boot_table_init (void);
+int acpi_mps_check (void);
 int acpi_numa_init (void);
 
 int acpi_table_init (void);
@@ -250,6 +251,11 @@ static inline int acpi_boot_table_init(void)
        return 0;
 }
 
+static inline int acpi_mps_check(void)
+{
+       return 0;
+}
+
 static inline int acpi_check_resource_conflict(struct resource *res)
 {
        return 0;
index 61c15eaf3fb3d8f309cd604380f0574f9547749f..0933a14e641423f523d8ed7a56ef7f2a6b849e5c 100644 (file)
@@ -64,6 +64,7 @@ struct bio_vec {
 
 struct bio_set;
 struct bio;
+struct bio_integrity_payload;
 typedef void (bio_end_io_t) (struct bio *, int);
 typedef void (bio_destructor_t) (struct bio *);
 
@@ -112,6 +113,9 @@ struct bio {
        atomic_t                bi_cnt;         /* pin count */
 
        void                    *bi_private;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       struct bio_integrity_payload *bi_integrity;  /* data integrity */
+#endif
 
        bio_destructor_t        *bi_destructor; /* destructor */
 };
@@ -271,6 +275,29 @@ static inline void *bio_data(struct bio *bio)
  */
 #define bio_get(bio)   atomic_inc(&(bio)->bi_cnt)
 
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+/*
+ * bio integrity payload
+ */
+struct bio_integrity_payload {
+       struct bio              *bip_bio;       /* parent bio */
+       struct bio_vec          *bip_vec;       /* integrity data vector */
+
+       sector_t                bip_sector;     /* virtual start sector */
+
+       void                    *bip_buf;       /* generated integrity data */
+       bio_end_io_t            *bip_end_io;    /* saved I/O completion fn */
+
+       int                     bip_error;      /* saved I/O error */
+       unsigned int            bip_size;
+
+       unsigned short          bip_pool;       /* pool the ivec came from */
+       unsigned short          bip_vcnt;       /* # of integrity bio_vecs */
+       unsigned short          bip_idx;        /* current bip_vec index */
+
+       struct work_struct      bip_work;       /* I/O completion */
+};
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
 
 /*
  * A bio_pair is used when we need to split a bio.
@@ -283,10 +310,14 @@ static inline void *bio_data(struct bio *bio)
  *   in bio2.bi_private
  */
 struct bio_pair {
-       struct bio      bio1, bio2;
-       struct bio_vec  bv1, bv2;
-       atomic_t        cnt;
-       int             error;
+       struct bio                      bio1, bio2;
+       struct bio_vec                  bv1, bv2;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       struct bio_integrity_payload    bip1, bip2;
+       struct bio_vec                  iv1, iv2;
+#endif
+       atomic_t                        cnt;
+       int                             error;
 };
 extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool,
                                  int first_sectors);
@@ -333,6 +364,39 @@ extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *,
                                     int, int);
 extern int bio_uncopy_user(struct bio *);
 void zero_fill_bio(struct bio *bio);
+extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *);
+extern unsigned int bvec_nr_vecs(unsigned short idx);
+
+/*
+ * bio_set is used to allow other portions of the IO system to
+ * allocate their own private memory pools for bio and iovec structures.
+ * These memory pools in turn all allocate from the bio_slab
+ * and the bvec_slabs[].
+ */
+#define BIO_POOL_SIZE 2
+#define BIOVEC_NR_POOLS 6
+
+struct bio_set {
+       mempool_t *bio_pool;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       mempool_t *bio_integrity_pool;
+#endif
+       mempool_t *bvec_pools[BIOVEC_NR_POOLS];
+};
+
+struct biovec_slab {
+       int nr_vecs;
+       char *name;
+       struct kmem_cache *slab;
+};
+
+extern struct bio_set *fs_bio_set;
+
+/*
+ * a small number of entries is fine, not going to be performance critical.
+ * basically we just need to survive
+ */
+#define BIO_SPLIT_ENTRIES 2
 
 #ifdef CONFIG_HIGHMEM
 /*
@@ -381,5 +445,63 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx,
        __bio_kmap_irq((bio), (bio)->bi_idx, (flags))
 #define bio_kunmap_irq(buf,flags)      __bio_kunmap_irq(buf, flags)
 
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+
+#define bip_vec_idx(bip, idx)  (&(bip->bip_vec[(idx)]))
+#define bip_vec(bip)           bip_vec_idx(bip, 0)
+
+#define __bip_for_each_vec(bvl, bip, i, start_idx)                     \
+       for (bvl = bip_vec_idx((bip), (start_idx)), i = (start_idx);    \
+            i < (bip)->bip_vcnt;                                       \
+            bvl++, i++)
+
+#define bip_for_each_vec(bvl, bip, i)                                  \
+       __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx)
+
+static inline int bio_integrity(struct bio *bio)
+{
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       return bio->bi_integrity != NULL;
+#else
+       return 0;
+#endif
+}
+
+extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *);
+extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
+extern void bio_integrity_free(struct bio *, struct bio_set *);
+extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
+extern int bio_integrity_enabled(struct bio *bio);
+extern int bio_integrity_set_tag(struct bio *, void *, unsigned int);
+extern int bio_integrity_get_tag(struct bio *, void *, unsigned int);
+extern int bio_integrity_prep(struct bio *);
+extern void bio_integrity_endio(struct bio *, int);
+extern void bio_integrity_advance(struct bio *, unsigned int);
+extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
+extern void bio_integrity_split(struct bio *, struct bio_pair *, int);
+extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *);
+extern int bioset_integrity_create(struct bio_set *, int);
+extern void bioset_integrity_free(struct bio_set *);
+extern void bio_integrity_init_slab(void);
+
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+
+#define bio_integrity(a)               (0)
+#define bioset_integrity_create(a, b)  (0)
+#define bio_integrity_prep(a)          (0)
+#define bio_integrity_enabled(a)       (0)
+#define bio_integrity_clone(a, b, c)   (0)
+#define bioset_integrity_free(a)       do { } while (0)
+#define bio_integrity_free(a, b)       do { } while (0)
+#define bio_integrity_endio(a, b)      do { } while (0)
+#define bio_integrity_advance(a, b)    do { } while (0)
+#define bio_integrity_trim(a, b, c)    do { } while (0)
+#define bio_integrity_split(a, b, c)   do { } while (0)
+#define bio_integrity_set_tag(a, b, c) do { } while (0)
+#define bio_integrity_get_tag(a, b, c) do { } while (0)
+#define bio_integrity_init_slab(a)     do { } while (0)
+
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
+
 #endif /* CONFIG_BLOCK */
 #endif /* __LINUX_BIO_H */
index d2a1b71e93c3eee9570e86513bdb2786d260699c..1ffd8bfdc4c94956fa14bb8e6c880d79e0953918 100644 (file)
@@ -23,7 +23,6 @@
 struct scsi_ioctl_command;
 
 struct request_queue;
-typedef struct request_queue request_queue_t __deprecated;
 struct elevator_queue;
 typedef struct elevator_queue elevator_t;
 struct request_pm_state;
@@ -34,12 +33,6 @@ struct sg_io_hdr;
 #define BLKDEV_MIN_RQ  4
 #define BLKDEV_MAX_RQ  128     /* Default maximum */
 
-int put_io_context(struct io_context *ioc);
-void exit_io_context(void);
-struct io_context *get_io_context(gfp_t gfp_flags, int node);
-struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
-void copy_io_context(struct io_context **pdst, struct io_context **psrc);
-
 struct request;
 typedef void (rq_end_io_fn)(struct request *, int);
 
@@ -113,6 +106,7 @@ enum rq_flag_bits {
        __REQ_ALLOCED,          /* request came from our alloc pool */
        __REQ_RW_META,          /* metadata io request */
        __REQ_COPY_USER,        /* contains copies of user pages */
+       __REQ_INTEGRITY,        /* integrity metadata has been remapped */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -135,6 +129,7 @@ enum rq_flag_bits {
 #define REQ_ALLOCED    (1 << __REQ_ALLOCED)
 #define REQ_RW_META    (1 << __REQ_RW_META)
 #define REQ_COPY_USER  (1 << __REQ_COPY_USER)
+#define REQ_INTEGRITY  (1 << __REQ_INTEGRITY)
 
 #define BLK_MAX_CDB    16
 
@@ -259,7 +254,14 @@ typedef int (prep_rq_fn) (struct request_queue *, struct request *);
 typedef void (unplug_fn) (struct request_queue *);
 
 struct bio_vec;
-typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *);
+struct bvec_merge_data {
+       struct block_device *bi_bdev;
+       sector_t bi_sector;
+       unsigned bi_size;
+       unsigned long bi_rw;
+};
+typedef int (merge_bvec_fn) (struct request_queue *, struct bvec_merge_data *,
+                            struct bio_vec *);
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
 typedef int (dma_drain_needed_fn)(struct request *);
@@ -426,6 +428,32 @@ static inline void queue_flag_set_unlocked(unsigned int flag,
        __set_bit(flag, &q->queue_flags);
 }
 
+static inline int queue_flag_test_and_clear(unsigned int flag,
+                                           struct request_queue *q)
+{
+       WARN_ON_ONCE(!queue_is_locked(q));
+
+       if (test_bit(flag, &q->queue_flags)) {
+               __clear_bit(flag, &q->queue_flags);
+               return 1;
+       }
+
+       return 0;
+}
+
+static inline int queue_flag_test_and_set(unsigned int flag,
+                                         struct request_queue *q)
+{
+       WARN_ON_ONCE(!queue_is_locked(q));
+
+       if (!test_bit(flag, &q->queue_flags)) {
+               __set_bit(flag, &q->queue_flags);
+               return 0;
+       }
+
+       return 1;
+}
+
 static inline void queue_flag_set(unsigned int flag, struct request_queue *q)
 {
        WARN_ON_ONCE(!queue_is_locked(q));
@@ -676,7 +704,6 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *,
                          struct request *, int);
 extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
                                  struct request *, int, rq_end_io_fn *);
-extern int blk_verify_command(unsigned char *, int);
 extern void blk_unplug(struct request_queue *q);
 
 static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
@@ -749,6 +776,7 @@ 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_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);
 extern int blk_queue_dma_drain(struct request_queue *q,
                               dma_drain_needed_fn *dma_drain_needed,
                               void *buf, unsigned int size);
@@ -802,6 +830,15 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
 
 extern int blkdev_issue_flush(struct block_device *, sector_t *);
 
+/*
+* command filter functions
+*/
+extern int blk_verify_command(struct file *file, unsigned char *cmd);
+extern int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter,
+                                        unsigned char *cmd, mode_t *f_mode);
+extern int blk_register_filter(struct gendisk *disk);
+extern void blk_unregister_filter(struct gendisk *disk);
+
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
 #define SAFE_MAX_SECTORS 255
@@ -865,28 +902,116 @@ void kblockd_flush_work(struct work_struct *work);
 #define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \
        MODULE_ALIAS("block-major-" __stringify(major) "-*")
 
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
 
-#else /* CONFIG_BLOCK */
-/*
- * stubs for when the block layer is configured out
- */
-#define buffer_heads_over_limit 0
+#define INTEGRITY_FLAG_READ    2       /* verify data integrity on read */
+#define INTEGRITY_FLAG_WRITE   4       /* generate data integrity on write */
 
-static inline long nr_blockdev_pages(void)
+struct blk_integrity_exchg {
+       void                    *prot_buf;
+       void                    *data_buf;
+       sector_t                sector;
+       unsigned int            data_size;
+       unsigned short          sector_size;
+       const char              *disk_name;
+};
+
+typedef void (integrity_gen_fn) (struct blk_integrity_exchg *);
+typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *);
+typedef void (integrity_set_tag_fn) (void *, void *, unsigned int);
+typedef void (integrity_get_tag_fn) (void *, void *, unsigned int);
+
+struct blk_integrity {
+       integrity_gen_fn        *generate_fn;
+       integrity_vrfy_fn       *verify_fn;
+       integrity_set_tag_fn    *set_tag_fn;
+       integrity_get_tag_fn    *get_tag_fn;
+
+       unsigned short          flags;
+       unsigned short          tuple_size;
+       unsigned short          sector_size;
+       unsigned short          tag_size;
+
+       const char              *name;
+
+       struct kobject          kobj;
+};
+
+extern int blk_integrity_register(struct gendisk *, struct blk_integrity *);
+extern void blk_integrity_unregister(struct gendisk *);
+extern int blk_integrity_compare(struct block_device *, struct block_device *);
+extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *);
+extern int blk_rq_count_integrity_sg(struct request *);
+
+static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi)
 {
+       if (bi)
+               return bi->tuple_size;
+
        return 0;
 }
 
-static inline void exit_io_context(void)
+static inline struct blk_integrity *bdev_get_integrity(struct block_device *bdev)
 {
+       return bdev->bd_disk->integrity;
 }
 
-struct io_context;
-static inline int put_io_context(struct io_context *ioc)
+static inline unsigned int bdev_get_tag_size(struct block_device *bdev)
 {
-       return 1;
+       struct blk_integrity *bi = bdev_get_integrity(bdev);
+
+       if (bi)
+               return bi->tag_size;
+
+       return 0;
+}
+
+static inline int bdev_integrity_enabled(struct block_device *bdev, int rw)
+{
+       struct blk_integrity *bi = bdev_get_integrity(bdev);
+
+       if (bi == NULL)
+               return 0;
+
+       if (rw == READ && bi->verify_fn != NULL &&
+           (bi->flags & INTEGRITY_FLAG_READ))
+               return 1;
+
+       if (rw == WRITE && bi->generate_fn != NULL &&
+           (bi->flags & INTEGRITY_FLAG_WRITE))
+               return 1;
+
+       return 0;
 }
 
+static inline int blk_integrity_rq(struct request *rq)
+{
+       return bio_integrity(rq->bio);
+}
+
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+
+#define blk_integrity_rq(rq)                   (0)
+#define blk_rq_count_integrity_sg(a)           (0)
+#define blk_rq_map_integrity_sg(a, b)          (0)
+#define bdev_get_integrity(a)                  (0)
+#define bdev_get_tag_size(a)                   (0)
+#define blk_integrity_compare(a, b)            (0)
+#define blk_integrity_register(a, b)           (0)
+#define blk_integrity_unregister(a)            do { } while (0);
+
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
+
+#else /* CONFIG_BLOCK */
+/*
+ * stubs for when the block layer is configured out
+ */
+#define buffer_heads_over_limit 0
+
+static inline long nr_blockdev_pages(void)
+{
+       return 0;
+}
 
 #endif /* CONFIG_BLOCK */
 
index e3ef903aae88224fef2f43fa96b0e0f199baa09b..d084b8d227a52fb978c02a4f07d98e08b653502b 100644 (file)
@@ -129,6 +129,7 @@ struct blk_trace {
        u32 dev;
        struct dentry *dir;
        struct dentry *dropped_file;
+       struct dentry *msg_file;
        atomic_t dropped;
 };
 
index 686895bacd9dcc8500518d4bddc3629ec9533dd4..a1d9b79078ea03425cb1ce4ae8746daf01c46fd5 100644 (file)
@@ -84,6 +84,8 @@ extern int reserve_bootmem(unsigned long addr, unsigned long size, int flags);
        __alloc_bootmem_low(x, PAGE_SIZE, 0)
 #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
 
+extern int reserve_bootmem_generic(unsigned long addr, unsigned long size,
+                                  int flags);
 extern unsigned long free_all_bootmem(void);
 extern unsigned long free_all_bootmem_node(pg_data_t *pgdat);
 extern void *__alloc_bootmem_node(pg_data_t *pgdat,
index a4f27fbdf5494ee885caa967a24d1934744386a3..248e6e3b9b734d515e0c74f95aabd1de2dd57b6d 100644 (file)
@@ -108,6 +108,8 @@ struct console {
        struct   console *next;
 };
 
+extern int console_set_on_cmdline;
+
 extern int add_preferred_console(char *name, int idx, char *options);
 extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options);
 extern void register_console(struct console *);
index 425824bd49f308f64074943fd257bd69f512edce..c43dc47fdf75e8127498a79290c6c10ef4b945e8 100644 (file)
  */
 #define CRYPTO_ALG_TYPE_MASK           0x0000000f
 #define CRYPTO_ALG_TYPE_CIPHER         0x00000001
-#define CRYPTO_ALG_TYPE_DIGEST         0x00000002
-#define CRYPTO_ALG_TYPE_HASH           0x00000003
+#define CRYPTO_ALG_TYPE_COMPRESS       0x00000002
+#define CRYPTO_ALG_TYPE_AEAD           0x00000003
 #define CRYPTO_ALG_TYPE_BLKCIPHER      0x00000004
 #define CRYPTO_ALG_TYPE_ABLKCIPHER     0x00000005
 #define CRYPTO_ALG_TYPE_GIVCIPHER      0x00000006
-#define CRYPTO_ALG_TYPE_COMPRESS       0x00000008
-#define CRYPTO_ALG_TYPE_AEAD           0x00000009
+#define CRYPTO_ALG_TYPE_DIGEST         0x00000008
+#define CRYPTO_ALG_TYPE_HASH           0x00000009
+#define CRYPTO_ALG_TYPE_AHASH          0x0000000a
 
 #define CRYPTO_ALG_TYPE_HASH_MASK      0x0000000e
+#define CRYPTO_ALG_TYPE_AHASH_MASK     0x0000000c
 #define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c
 
 #define CRYPTO_ALG_LARVAL              0x00000010
@@ -102,6 +104,7 @@ struct crypto_async_request;
 struct crypto_aead;
 struct crypto_blkcipher;
 struct crypto_hash;
+struct crypto_ahash;
 struct crypto_tfm;
 struct crypto_type;
 struct aead_givcrypt_request;
@@ -131,6 +134,16 @@ struct ablkcipher_request {
        void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
+struct ahash_request {
+       struct crypto_async_request base;
+
+       unsigned int nbytes;
+       struct scatterlist *src;
+       u8                 *result;
+
+       void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
 /**
  *     struct aead_request - AEAD request
  *     @base: Common attributes for async crypto requests
@@ -195,6 +208,17 @@ struct ablkcipher_alg {
        unsigned int ivsize;
 };
 
+struct ahash_alg {
+       int (*init)(struct ahash_request *req);
+       int (*update)(struct ahash_request *req);
+       int (*final)(struct ahash_request *req);
+       int (*digest)(struct ahash_request *req);
+       int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
+                       unsigned int keylen);
+
+       unsigned int digestsize;
+};
+
 struct aead_alg {
        int (*setkey)(struct crypto_aead *tfm, const u8 *key,
                      unsigned int keylen);
@@ -272,6 +296,7 @@ struct compress_alg {
 #define cra_cipher     cra_u.cipher
 #define cra_digest     cra_u.digest
 #define cra_hash       cra_u.hash
+#define cra_ahash      cra_u.ahash
 #define cra_compress   cra_u.compress
 
 struct crypto_alg {
@@ -298,6 +323,7 @@ struct crypto_alg {
                struct cipher_alg cipher;
                struct digest_alg digest;
                struct hash_alg hash;
+               struct ahash_alg ahash;
                struct compress_alg compress;
        } cra_u;
 
@@ -383,6 +409,18 @@ struct hash_tfm {
        unsigned int digestsize;
 };
 
+struct ahash_tfm {
+       int (*init)(struct ahash_request *req);
+       int (*update)(struct ahash_request *req);
+       int (*final)(struct ahash_request *req);
+       int (*digest)(struct ahash_request *req);
+       int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
+                       unsigned int keylen);
+
+       unsigned int digestsize;
+       unsigned int reqsize;
+};
+
 struct compress_tfm {
        int (*cot_compress)(struct crypto_tfm *tfm,
                            const u8 *src, unsigned int slen,
@@ -397,6 +435,7 @@ struct compress_tfm {
 #define crt_blkcipher  crt_u.blkcipher
 #define crt_cipher     crt_u.cipher
 #define crt_hash       crt_u.hash
+#define crt_ahash      crt_u.ahash
 #define crt_compress   crt_u.compress
 
 struct crypto_tfm {
@@ -409,6 +448,7 @@ struct crypto_tfm {
                struct blkcipher_tfm blkcipher;
                struct cipher_tfm cipher;
                struct hash_tfm hash;
+               struct ahash_tfm ahash;
                struct compress_tfm compress;
        } crt_u;
        
index 54552d21296efe9037de1d034ef45cafa4199067..fd832c6d419efc377a698eecd146032d5f68a8d1 100644 (file)
@@ -41,6 +41,7 @@ static inline void ndelay(unsigned long x)
 #define ndelay(x) ndelay(x)
 #endif
 
+extern unsigned long lpj_fine;
 void calibrate_delay(void);
 void msleep(unsigned int msecs);
 unsigned long msleep_interruptible(unsigned int msecs);
index a5f359a7ad0ef84d2829872f904f50014abe71f9..807373d467f7485a03dfa1417f16a62097108e17 100644 (file)
@@ -287,7 +287,6 @@ efi_guid_unparse(efi_guid_t *guid, char *out)
 extern void efi_init (void);
 extern void *efi_get_pal_addr (void);
 extern void efi_map_pal_code (void);
-extern void efi_map_memmap(void);
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timespec *ts);
 extern void efi_enter_virtual_mode (void);     /* switch EFI to virtual mode, if possible */
@@ -295,14 +294,11 @@ extern u64 efi_get_iobase (void);
 extern u32 efi_mem_type (unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
 extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
-extern int efi_mem_attribute_range (unsigned long phys_addr, unsigned long size,
-                                   u64 attr);
 extern int __init efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
                struct resource *data_resource, struct resource *bss_resource);
 extern unsigned long efi_get_time(void);
 extern int efi_set_rtc_mmss(unsigned long nowtime);
-extern int is_available_memory(efi_memory_desc_t * md);
 extern struct efi_memory_map memmap;
 
 /**
diff --git a/include/linux/firmware-map.h b/include/linux/firmware-map.h
new file mode 100644 (file)
index 0000000..acbdbcc
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * include/linux/firmware-map.h:
+ *  Copyright (C) 2008 SUSE LINUX Products GmbH
+ *  by Bernhard Walle <bwalle@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 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.
+ *
+ */
+#ifndef _LINUX_FIRMWARE_MAP_H
+#define _LINUX_FIRMWARE_MAP_H
+
+#include <linux/list.h>
+#include <linux/kobject.h>
+
+/*
+ * provide a dummy interface if CONFIG_FIRMWARE_MEMMAP is disabled
+ */
+#ifdef CONFIG_FIRMWARE_MEMMAP
+
+/**
+ * Adds a firmware mapping entry. This function uses kmalloc() for memory
+ * allocation. Use firmware_map_add_early() if you want to use the bootmem
+ * allocator.
+ *
+ * That function must be called before late_initcall.
+ *
+ * @start: Start of the memory range.
+ * @end:   End of the memory range (inclusive).
+ * @type:  Type of the memory range.
+ *
+ * Returns 0 on success, or -ENOMEM if no memory could be allocated.
+ */
+int firmware_map_add(resource_size_t start, resource_size_t end,
+                    const char *type);
+
+/**
+ * Adds a firmware mapping entry. This function uses the bootmem allocator
+ * for memory allocation. Use firmware_map_add() if you want to use kmalloc().
+ *
+ * That function must be called before late_initcall.
+ *
+ * @start: Start of the memory range.
+ * @end:   End of the memory range (inclusive).
+ * @type:  Type of the memory range.
+ *
+ * Returns 0 on success, or -ENOMEM if no memory could be allocated.
+ */
+int firmware_map_add_early(resource_size_t start, resource_size_t end,
+                          const char *type);
+
+#else /* CONFIG_FIRMWARE_MEMMAP */
+
+static inline int firmware_map_add(resource_size_t start, resource_size_t end,
+                                  const char *type)
+{
+       return 0;
+}
+
+static inline int firmware_map_add_early(resource_size_t start,
+                                        resource_size_t end, const char *type)
+{
+       return 0;
+}
+
+#endif /* CONFIG_FIRMWARE_MEMMAP */
+
+#endif /* _LINUX_FIRMWARE_MAP_H */
index ae7aec3cabee67ef4fb9c6440b8ec14dd76c5207..e8787417f65a1175cb4e1542f7271c0d3dbfd87b 100644 (file)
@@ -110,6 +110,14 @@ struct hd_struct {
 #define GENHD_FL_SUPPRESS_PARTITION_INFO       32
 #define GENHD_FL_FAIL                          64
 
+#define BLK_SCSI_MAX_CMDS      (256)
+#define BLK_SCSI_CMD_PER_LONG  (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
+
+struct blk_scsi_cmd_filter {
+       unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
+       unsigned long write_ok[BLK_SCSI_CMD_PER_LONG];
+       struct kobject kobj;
+};
 
 struct gendisk {
        int major;                      /* major number of driver */
@@ -120,6 +128,7 @@ struct gendisk {
        struct hd_struct **part;        /* [indexed by minor] */
        struct block_device_operations *fops;
        struct request_queue *queue;
+       struct blk_scsi_cmd_filter cmd_filter;
        void *private_data;
        sector_t capacity;
 
@@ -141,6 +150,9 @@ struct gendisk {
        struct disk_stats dkstats;
 #endif
        struct work_struct async_notify;
+#ifdef  CONFIG_BLK_DEV_INTEGRITY
+       struct blk_integrity *integrity;
+#endif
 };
 
 /* 
index 2b7a1187cb29a804988d686be4c8a8d088d6356f..08b987bccf89aff533268c0718770583ba204026 100644 (file)
@@ -99,4 +99,22 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc)
        return NULL;
 }
 
+#ifdef CONFIG_BLOCK
+int put_io_context(struct io_context *ioc);
+void exit_io_context(void);
+struct io_context *get_io_context(gfp_t gfp_flags, int node);
+struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
+void copy_io_context(struct io_context **pdst, struct io_context **psrc);
+#else
+static inline void exit_io_context(void)
+{
+}
+
+struct io_context;
+static inline int put_io_context(struct io_context *ioc)
+{
+       return 1;
+}
+#endif
+
 #endif
index e8ffce898bf913c7c12943b0a40785354dde6834..cf9f40a91c9c79837753956b135e49c9ec984630 100644 (file)
@@ -1,11 +1,11 @@
 #ifndef _LINUX_KERNEL_STAT_H
 #define _LINUX_KERNEL_STAT_H
 
-#include <asm/irq.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
 #include <linux/percpu.h>
 #include <linux/cpumask.h>
+#include <asm/irq.h>
 #include <asm/cputime.h>
 
 /*
index 2119610b24f812fe1c80a6f806c679af11d56ab9..9fd1f859021b5018baffdb440261379dab4a55b3 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_LINKAGE_H
 #define _LINUX_LINKAGE_H
 
+#include <linux/compiler.h>
 #include <asm/linkage.h>
 
 #ifdef __cplusplus
@@ -17,6 +18,9 @@
 # define asmregparm
 #endif
 
+#define __page_aligned_data    __section(.data.page_aligned) __aligned(PAGE_SIZE)
+#define __page_aligned_bss     __section(.bss.page_aligned) __aligned(PAGE_SIZE)
+
 /*
  * This is used by architectures to keep arguments on the stack
  * untouched by the compiler by keeping them live until the end.
index 586a943cab018647da208582bc1f19e0dc485f1d..cf1cd3a2ed7870c6faa00a3452ab7ef1339d33ee 100644 (file)
@@ -998,8 +998,8 @@ extern void free_area_init_node(int nid, pg_data_t *pgdat,
 extern void free_area_init_nodes(unsigned long *max_zone_pfn);
 extern void add_active_range(unsigned int nid, unsigned long start_pfn,
                                        unsigned long end_pfn);
-extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
-                                               unsigned long new_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);
@@ -1011,6 +1011,8 @@ extern unsigned long find_min_pfn_with_active_regions(void);
 extern unsigned long find_max_pfn_with_active_regions(void);
 extern void free_bootmem_with_active_regions(int nid,
                                                unsigned long max_low_pfn);
+typedef int (*work_fn_t)(unsigned long, unsigned long, void *);
+extern void work_with_active_regions(int nid, work_fn_t work_fn, void *data);
 extern void sparse_memory_present_with_active_regions(int nid);
 #ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
 extern int early_pfn_to_nid(unsigned long pfn);
@@ -1024,6 +1026,7 @@ extern void mem_init(void);
 extern void show_mem(void);
 extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);
+extern int after_bootmem;
 
 #ifdef CONFIG_NUMA
 extern void setup_per_cpu_pageset(void);
index 69b2342d5ebb81954ad9bcf3df568aa7d6585ada..c4db5827963d98a5624ec1c8fb637ad959903a75 100644 (file)
@@ -159,6 +159,15 @@ struct ap_device_id {
 
 #define AP_DEVICE_ID_MATCH_DEVICE_TYPE         0x01
 
+/* s390 css bus devices (subchannels) */
+struct css_device_id {
+       __u8 match_flags;
+       __u8 type; /* subchannel type */
+       __u16 pad2;
+       __u32 pad3;
+       kernel_ulong_t driver_data;
+};
+
 #define ACPI_ID_LEN    16 /* only 9 bytes needed here, 16 bytes are used */
                           /* to workaround crosscompile issues */
 
index f31debfac926a93cf921b2ec4a532e00b535de23..0d2a4e7012aa4663722527bba42c99e4b3b2a6a6 100644 (file)
@@ -157,6 +157,7 @@ PAGEFLAG(Active, active) __CLEARPAGEFLAG(Active, active)
 __PAGEFLAG(Slab, slab)
 PAGEFLAG(Checked, owner_priv_1)                /* Used by some filesystems */
 PAGEFLAG(Pinned, owner_priv_1) TESTSCFLAG(Pinned, owner_priv_1) /* Xen */
+PAGEFLAG(SavePinned, dirty);                                   /* Xen */
 PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
 PAGEFLAG(Private, private) __CLEARPAGEFLAG(Private, private)
        __SETPAGEFLAG(Private, private)
index e875905f7b12c3ed8a057ca235ff3fa41e72fcf2..e8c06122be36058f88cb6e291360eb2c0ebe09a0 100644 (file)
 
 #include <linux/types.h>
 
-/* Macro to aid the definition of ranges of bits */
-#define PB_range(name, required_bits) \
-       name, name ## _end = (name + required_bits) - 1
-
 /* Bit indices that affect a whole block of pages */
 enum pageblock_bits {
-       PB_range(PB_migrate, 3), /* 3 bits required for migrate types */
+       PB_migrate,
+       PB_migrate_end = PB_migrate + 3 - 1,
+                       /* 3 bits required for migrate types */
        NR_PAGEBLOCK_BITS
 };
 
index f98501ba557eea676a827aed770d57b0b4b12c56..c6f5f9dd0cee41636f282237e0ccfacf07586f96 100644 (file)
@@ -95,8 +95,12 @@ extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
 extern void ptrace_untrace(struct task_struct *child);
-extern int ptrace_may_attach(struct task_struct *task);
-extern int __ptrace_may_attach(struct task_struct *task);
+#define PTRACE_MODE_READ   1
+#define PTRACE_MODE_ATTACH 2
+/* Returns 0 on success, -errno on denial. */
+extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
+/* Returns true on success, false on denial. */
+extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
 
 static inline int ptrace_reparented(struct task_struct *child)
 {
index f3f4f28c6960cfabce8efd60f974f8d6dfd7eb62..c9ba2fdf807d5cbca878d5873ef38ca50332a201 100644 (file)
@@ -8,7 +8,7 @@ extern int pm_trace_enabled;
 
 struct device;
 extern void set_trace_device(struct device *);
-extern void generate_resume_trace(void *tracedata, unsigned int user);
+extern void generate_resume_trace(const void *tracedata, unsigned int user);
 
 #define TRACE_DEVICE(dev) do { \
        if (pm_trace_enabled) \
index 50737c70e78ea41e2a2e4551b6044df86f8a1de3..31c8851ec5d0fba51ceab47da8d76f424f7e0345 100644 (file)
@@ -46,7 +46,8 @@ struct audit_krule;
  */
 extern int cap_capable(struct task_struct *tsk, int cap);
 extern int cap_settime(struct timespec *ts, struct timezone *tz);
-extern int cap_ptrace(struct task_struct *parent, struct task_struct *child);
+extern int cap_ptrace(struct task_struct *parent, struct task_struct *child,
+                     unsigned int mode);
 extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
 extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
 extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@ -79,6 +80,7 @@ struct xfrm_selector;
 struct xfrm_policy;
 struct xfrm_state;
 struct xfrm_user_sec_ctx;
+struct seq_file;
 
 extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
 extern int cap_netlink_recv(struct sk_buff *skb, int cap);
@@ -289,10 +291,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Update module state after a successful pivot.
  *     @old_path contains the path for the old root.
  *     @new_path contains the path for the new root.
- * @sb_get_mnt_opts:
- *     Get the security relevant mount options used for a superblock
- *     @sb the superblock to get security mount options from
- *     @opts binary data structure containing all lsm mount data
  * @sb_set_mnt_opts:
  *     Set the security relevant mount options used for a superblock
  *     @sb the superblock to set security mount options for
@@ -1170,6 +1168,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     attributes would be changed by the execve.
  *     @parent contains the task_struct structure for parent process.
  *     @child contains the task_struct structure for child process.
+ *     @mode contains the PTRACE_MODE flags indicating the form of access.
  *     Return 0 if permission is granted.
  * @capget:
  *     Get the @effective, @inheritable, and @permitted capability sets for
@@ -1240,11 +1239,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @pages contains the number of pages.
  *     Return 0 if permission is granted.
  *
- * @register_security:
- *     allow module stacking.
- *     @name contains the name of the security module being stacked.
- *     @ops contains a pointer to the struct security_operations of the module to stack.
- *
  * @secid_to_secctx:
  *     Convert secid to security context.
  *     @secid contains the security ID.
@@ -1295,7 +1289,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 struct security_operations {
        char name[SECURITY_NAME_MAX + 1];
 
-       int (*ptrace) (struct task_struct *parent, struct task_struct *child);
+       int (*ptrace) (struct task_struct *parent, struct task_struct *child,
+                      unsigned int mode);
        int (*capget) (struct task_struct *target,
                       kernel_cap_t *effective,
                       kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@ -1328,6 +1323,7 @@ struct security_operations {
        void (*sb_free_security) (struct super_block *sb);
        int (*sb_copy_data) (char *orig, char *copy);
        int (*sb_kern_mount) (struct super_block *sb, void *data);
+       int (*sb_show_options) (struct seq_file *m, struct super_block *sb);
        int (*sb_statfs) (struct dentry *dentry);
        int (*sb_mount) (char *dev_name, struct path *path,
                         char *type, unsigned long flags, void *data);
@@ -1343,8 +1339,6 @@ struct security_operations {
                             struct path *new_path);
        void (*sb_post_pivotroot) (struct path *old_path,
                                   struct path *new_path);
-       int (*sb_get_mnt_opts) (const struct super_block *sb,
-                               struct security_mnt_opts *opts);
        int (*sb_set_mnt_opts) (struct super_block *sb,
                                struct security_mnt_opts *opts);
        void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
@@ -1472,10 +1466,6 @@ struct security_operations {
        int (*netlink_send) (struct sock *sk, struct sk_buff *skb);
        int (*netlink_recv) (struct sk_buff *skb, int cap);
 
-       /* allow module stacking */
-       int (*register_security) (const char *name,
-                                 struct security_operations *ops);
-
        void (*d_instantiate) (struct dentry *dentry, struct inode *inode);
 
        int (*getprocattr) (struct task_struct *p, char *name, char **value);
@@ -1565,7 +1555,6 @@ struct security_operations {
 extern int security_init(void);
 extern int security_module_enable(struct security_operations *ops);
 extern int register_security(struct security_operations *ops);
-extern int mod_reg_security(const char *name, struct security_operations *ops);
 extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
                                             struct dentry *parent, void *data,
                                             const struct file_operations *fops);
@@ -1573,7 +1562,8 @@ extern struct dentry *securityfs_create_dir(const char *name, struct dentry *par
 extern void securityfs_remove(struct dentry *dentry);
 
 /* Security operations */
-int security_ptrace(struct task_struct *parent, struct task_struct *child);
+int security_ptrace(struct task_struct *parent, struct task_struct *child,
+                   unsigned int mode);
 int security_capget(struct task_struct *target,
                    kernel_cap_t *effective,
                    kernel_cap_t *inheritable,
@@ -1606,6 +1596,7 @@ int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
 int security_sb_copy_data(char *orig, char *copy);
 int security_sb_kern_mount(struct super_block *sb, void *data);
+int security_sb_show_options(struct seq_file *m, struct super_block *sb);
 int security_sb_statfs(struct dentry *dentry);
 int security_sb_mount(char *dev_name, struct path *path,
                      char *type, unsigned long flags, void *data);
@@ -1617,8 +1608,6 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d
 void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint);
 int security_sb_pivotroot(struct path *old_path, struct path *new_path);
 void security_sb_post_pivotroot(struct path *old_path, struct path *new_path);
-int security_sb_get_mnt_opts(const struct super_block *sb,
-                               struct security_mnt_opts *opts);
 int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
 void security_sb_clone_mnt_opts(const struct super_block *oldsb,
                                struct super_block *newsb);
@@ -1755,9 +1744,11 @@ static inline int security_init(void)
        return 0;
 }
 
-static inline int security_ptrace(struct task_struct *parent, struct task_struct *child)
+static inline int security_ptrace(struct task_struct *parent,
+                                 struct task_struct *child,
+                                 unsigned int mode)
 {
-       return cap_ptrace(parent, child);
+       return cap_ptrace(parent, child, mode);
 }
 
 static inline int security_capget(struct task_struct *target,
@@ -1881,6 +1872,12 @@ static inline int security_sb_kern_mount(struct super_block *sb, void *data)
        return 0;
 }
 
+static inline int security_sb_show_options(struct seq_file *m,
+                                          struct super_block *sb)
+{
+       return 0;
+}
+
 static inline int security_sb_statfs(struct dentry *dentry)
 {
        return 0;
@@ -1927,12 +1924,6 @@ static inline int security_sb_pivotroot(struct path *old_path,
 static inline void security_sb_post_pivotroot(struct path *old_path,
                                              struct path *new_path)
 { }
-static inline int security_sb_get_mnt_opts(const struct super_block *sb,
-                                          struct security_mnt_opts *opts)
-{
-       security_init_mnt_opts(opts);
-       return 0;
-}
 
 static inline int security_sb_set_mnt_opts(struct super_block *sb,
                                           struct security_mnt_opts *opts)
diff --git a/include/pcmcia/bulkmem.h b/include/pcmcia/bulkmem.h
deleted file mode 100644 (file)
index 6bc7472..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * bulkmem.h -- Definitions for bulk memory services
- *
- * 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.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * (C) 1999            David A. Hinds
- */
-
-#ifndef _LINUX_BULKMEM_H
-#define _LINUX_BULKMEM_H
-
-/* For GetFirstRegion and GetNextRegion */
-typedef struct region_info_t {
-    u_int              Attributes;
-    u_int              CardOffset;
-    u_int              RegionSize;
-    u_int              AccessSpeed;
-    u_int              BlockSize;
-    u_int              PartMultiple;
-    u_char             JedecMfr, JedecInfo;
-    memory_handle_t    next;
-} region_info_t;
-
-#define REGION_TYPE            0x0001
-#define REGION_TYPE_CM         0x0000
-#define REGION_TYPE_AM         0x0001
-#define REGION_PREFETCH                0x0008
-#define REGION_CACHEABLE       0x0010
-#define REGION_BAR_MASK                0xe000
-#define REGION_BAR_SHIFT       13
-
-int pcmcia_get_first_region(struct pcmcia_device *handle, region_info_t *rgn);
-int pcmcia_get_next_region(struct pcmcia_device *handle, region_info_t *rgn);
-
-#endif /* _LINUX_BULKMEM_H */
index d3bbb19caf8183def6fa7e6e22dce4753ae7a40a..e2e10c1e9a0615fc9844419ed9995f40f2d9f732 100644 (file)
@@ -595,7 +595,7 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple
 int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
 int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse);
 
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info);
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *count);
 
 /* ... but use these wrappers instead */
 #define pcmcia_get_first_tuple(p_dev, tuple) \
index 87a260e3699efd3dd138216e84038ed916064060..45d84b275789e3e138536bcac9ffff52e81a0df9 100644 (file)
@@ -373,9 +373,6 @@ struct pcmcia_socket;
 
 int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg);
 int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config);
-int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
-int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
-int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status);
 int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
 int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
index 9a6bcc4952f0653fbc8dafad010b3c87b9be11bf..f402a0f435b451ce6843a4e9fa7faaf4620ede61 100644 (file)
@@ -21,7 +21,8 @@
 #include <sys/types.h>
 #endif
 
-#if defined(__arm__) || defined(__mips__) || defined(__avr32__)
+#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \
+       defined(__bfin__)
 /* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
 typedef u_int   ioaddr_t;
 #else
@@ -33,9 +34,6 @@ typedef u_int event_t;
 typedef u_char cisdata_t;
 typedef u_short        page_t;
 
-struct pcmcia_device;
-typedef struct pcmcia_device *client_handle_t;
-
 struct window_t;
 typedef struct window_t *window_handle_t;
 
index f047a1fd64f803a887ce40430a7e14a86d0e4627..b316027c853d7845dc374591b5a3f4c155f8f03d 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/mod_devicetable.h>
 #endif
 
-#include <pcmcia/bulkmem.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/device_id.h>
 
@@ -51,6 +50,24 @@ typedef struct mtd_info_t {
     u_int              CardOffset;
 } mtd_info_t;
 
+typedef struct region_info_t {
+    u_int              Attributes;
+    u_int              CardOffset;
+    u_int              RegionSize;
+    u_int              AccessSpeed;
+    u_int              BlockSize;
+    u_int              PartMultiple;
+    u_char             JedecMfr, JedecInfo;
+    memory_handle_t    next;
+} region_info_t;
+#define REGION_TYPE            0x0001
+#define REGION_TYPE_CM         0x0000
+#define REGION_TYPE_AM         0x0001
+#define REGION_PREFETCH                0x0008
+#define REGION_CACHEABLE       0x0010
+#define REGION_BAR_MASK                0xe000
+#define REGION_BAR_SHIFT       13
+
 typedef union ds_ioctl_arg_t {
     adjust_t           adjust;
     config_info_t      config;
index f95dca077c1c2fdc8cc5c59562185fadc2c65ddd..ed919dd9bb5c29debac61ce496baa06ae6408c4f 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
 #ifdef CONFIG_CARDBUS
 #include <linux/pci.h>
 #endif
@@ -136,8 +135,14 @@ struct pccard_resource_ops {
        struct resource* (*find_mem)    (unsigned long base, unsigned long num,
                                         unsigned long align, int low,
                                         struct pcmcia_socket *s);
-       int     (*adjust_resource)      (struct pcmcia_socket *s,
-                                        adjust_t *adj);
+       int     (*add_io)               (struct pcmcia_socket *s,
+                                        unsigned int action,
+                                        unsigned long r_start,
+                                        unsigned long r_end);
+       int     (*add_mem)              (struct pcmcia_socket *s,
+                                        unsigned int action,
+                                        unsigned long r_start,
+                                        unsigned long r_end);
        int     (*init)                 (struct pcmcia_socket *s);
        void    (*exit)                 (struct pcmcia_socket *s);
 };
@@ -245,7 +250,6 @@ struct pcmcia_socket {
 
        struct task_struct              *thread;
        struct completion               thread_done;
-       wait_queue_head_t               thread_wait;
        spinlock_t                      thread_lock;    /* protects thread_events */
        unsigned int                    thread_events;
 
diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h
deleted file mode 100644 (file)
index 5ad9c5e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */
-
-/* This file will be removed, please don't include it */
diff --git a/include/sound/ad1843.h b/include/sound/ad1843.h
new file mode 100644 (file)
index 0000000..b236a9d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org>
+ * Copyright 2008 Thomas Bogendoerfer <tsbogend@franken.de>
+ */
+
+#ifndef __SOUND_AD1843_H
+#define __SOUND_AD1843_H
+
+struct snd_ad1843 {
+       void *chip;
+       int (*read)(void *chip, int reg);
+       int (*write)(void *chip, int reg, int val);
+};
+
+#define AD1843_GAIN_RECLEV 0
+#define AD1843_GAIN_LINE   1
+#define AD1843_GAIN_LINE_2 2
+#define AD1843_GAIN_MIC    3
+#define AD1843_GAIN_PCM_0  4
+#define AD1843_GAIN_PCM_1  5
+#define AD1843_GAIN_SIZE   (AD1843_GAIN_PCM_1+1)
+
+int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id);
+int ad1843_get_gain(struct snd_ad1843 *ad1843, int id);
+int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval);
+int ad1843_get_recsrc(struct snd_ad1843 *ad1843);
+int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc);
+void ad1843_setup_dac(struct snd_ad1843 *ad1843,
+                     unsigned int id,
+                     unsigned int framerate,
+                     snd_pcm_format_t fmt,
+                     unsigned int channels);
+void ad1843_shutdown_dac(struct snd_ad1843 *ad1843,
+                        unsigned int id);
+void ad1843_setup_adc(struct snd_ad1843 *ad1843,
+                     unsigned int framerate,
+                     snd_pcm_format_t fmt,
+                     unsigned int channels);
+void ad1843_shutdown_adc(struct snd_ad1843 *ad1843);
+int ad1843_init(struct snd_ad1843 *ad1843);
+
+#endif /* __SOUND_AD1843_H */
index 3dc1291f52db78e8f525801f1b79204180e91dbf..4721b4bba0538360cd808db6c6cc0f13db9a3c7a 100644 (file)
@@ -129,9 +129,6 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
 #define snd_ctl_unregister_ioctl_compat(fcn)
 #endif
 
-int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control);
-int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, struct snd_ctl_elem_value *control);
-
 static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 {
        return id->numid - kctl->id.numid;
index 695ee53488a382ab85d90f1deb5e3b83a5fe82e6..558b96284bd22eba399ff2e8f28147a5c46b2eb0 100644 (file)
@@ -412,13 +412,13 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
 
 #endif /* CONFIG_SND_DEBUG */
 
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
 /**
  * snd_printdd - debug printk
  * @format: format string
  *
  * Works like snd_printk() for debugging purposes.
- * Ignored when CONFIG_SND_DEBUG_DETECT is not set.
+ * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set.
  */
 #define snd_printdd(format, args...) snd_printk(format, ##args)
 #else
@@ -442,7 +442,7 @@ struct snd_pci_quirk {
        unsigned short subvendor;       /* PCI subvendor ID */
        unsigned short subdevice;       /* PCI subdevice ID */
        int value;                      /* value */
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        const char *name;               /* name of the device (optional) */
 #endif
 };
@@ -450,7 +450,7 @@ struct snd_pci_quirk {
 #define _SND_PCI_QUIRK_ID(vend,dev) \
        .subvendor = (vend), .subdevice = (dev)
 #define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)}
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
 #define SND_PCI_QUIRK(vend,dev,xname,val) \
        {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)}
 #else
index e8d1f3e31f9e5c1eebc42ab6be4cdb9a1d8b3ebf..92647532c454aff379a627492211fcfac96d7abc 100644 (file)
 #define CS4236_RIGHT_WAVE      0x1c    /* right wavetable serial port volume */
 #define CS4236_VERSION         0x9c    /* chip version and ID */
 
+/* definitions for extended registers - OPTI93X */
+#define OPTi931_AUX_LEFT_INPUT 0x10
+#define OPTi931_AUX_RIGHT_INPUT        0x11
+#define OPTi93X_MIC_LEFT_INPUT 0x14
+#define OPTi93X_MIC_RIGHT_INPUT        0x15
+#define OPTi93X_OUT_LEFT       0x16
+#define OPTi93X_OUT_RIGHT      0x17
+
 #endif /* __SOUND_CS4231_REGS_H */
index 66055d702aa3cadf6c77544a31df05ff248960f9..f0785f9f4ae4939fc6289f53d1572e9f7802f4b1 100644 (file)
@@ -58,6 +58,7 @@
 /* compatible, but clones */
 #define CS4231_HW_INTERWAVE     0x1000 /* InterWave chip */
 #define CS4231_HW_OPL3SA2       0x1101 /* OPL3-SA2 chip, similar to cs4231 */
+#define CS4231_HW_OPTI93X      0x1102  /* Opti 930/931/933 */
 
 /* defines for codec.hwshare */
 #define CS4231_HWSHARE_IRQ     (1<<0)
@@ -120,6 +121,8 @@ unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg);
 void snd_cs4231_mce_up(struct snd_cs4231 *chip);
 void snd_cs4231_mce_down(struct snd_cs4231 *chip);
 
+void snd_cs4231_overrange(struct snd_cs4231 *chip);
+
 irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id);
 
 const char *snd_cs4231_chip_id(struct snd_cs4231 *chip);
index 7b7b9b13b4ddd8d04c1cf6392d15c95d58972de0..10ee28eac018535da6f1e706b9c6189f90d46230 100644 (file)
@@ -1670,6 +1670,7 @@ struct snd_emu_chip_details {
        unsigned char spi_dac;      /* SPI interface for DAC */
        unsigned char i2c_adc;      /* I2C interface for ADC */
        unsigned char adc_1361t;    /* Use Philips 1361T ADC */
+       unsigned char invert_shared_spdif; /* analog/digital switch inverted */
        const char *driver;
        const char *name;
        const char *id;         /* for backward compatibility - can be NULL if not needed */
index f023c1b97f8caa93cee30e8ed91f27a270c3b7a1..3d9afb6a8c9cd86b5ead0d9ccccaa49614f47fd8 100644 (file)
@@ -105,7 +105,7 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp,
                              int cap, int type, int midi_channels, int midi_voices, char *portname);
 int snd_seq_event_port_detach(int client, int port);
 
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
 void snd_seq_autoload_lock(void);
 void snd_seq_autoload_unlock(void);
 #else
index a105b01e06d50dc3ccb8b8bcb527d64ea9b7cbe8..3030fdc6981d05b804ccb5e31d5d7d3fafd7565e 100644 (file)
 {      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
        .shift = wshift, .invert = winvert}
 
+/* generic register modifier widget */
+#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
+{      .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
+       .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
+       .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
+       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
+
 /* dapm kcontrol types */
 #define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -193,6 +200,7 @@ struct snd_soc_dapm_widget;
 enum snd_soc_dapm_type;
 struct snd_soc_dapm_path;
 struct snd_soc_dapm_pin;
+struct snd_soc_dapm_route;
 
 /* dapm controls */
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
@@ -205,25 +213,32 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
        const struct snd_soc_dapm_widget *widget);
+int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
+       const struct snd_soc_dapm_widget *widget,
+       int num);
 
 /* dapm path setup */
-int snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
+int  __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec,
        const char *sink_name, const char *control_name, const char *src_name);
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
 void snd_soc_dapm_free(struct snd_soc_device *socdev);
+int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
+                           const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
        int event);
-int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event);
+int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
+       enum snd_soc_bias_level level);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
 
-/* dapm audio endpoint control */
-int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
-       char *pin, int status);
-int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec);
+/* dapm audio pin control and status */
+int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
+int snd_soc_dapm_sync(struct snd_soc_codec *codec);
 
 /* dapm widget types */
 enum snd_soc_dapm_type {
@@ -245,6 +260,18 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_post,                      /* machine specific post widget - exec last */
 };
 
+/*
+ * DAPM audio route definition.
+ *
+ * Defines an audio route originating at source via control and finishing
+ * at sink.
+ */
+struct snd_soc_dapm_route {
+       const char *sink;
+       const char *control;
+       const char *source;
+};
+
 /* dapm audio path between two widgets */
 struct snd_soc_dapm_path {
        char *name;
@@ -277,6 +304,9 @@ struct snd_soc_dapm_widget {
        unsigned char shift;                    /* bits to shift */
        unsigned int saved_value;               /* widget saved value */
        unsigned int value;                             /* widget current value */
+       unsigned int mask;                      /* non-shifted mask */
+       unsigned int on_val;                    /* on state value */
+       unsigned int off_val;                   /* off state value */
        unsigned char power:1;                  /* block power status */
        unsigned char invert:1;                 /* invert the power bit */
        unsigned char active:1;                 /* active stream on DAC, ADC's */
index d3c8c033dff83b06d772e4dab9178f35413e17ff..1890d87c52042adc4d375953195a350d20e198ea 100644 (file)
        .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
        .private_value = (reg_left) | ((shift) << 8)  | \
                ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+#define SOC_DOUBLE_S8_TLV(xname, reg, min, max, tlv_array) \
+{      .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p  = (tlv_array), \
+       .info   = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
+       .put    = snd_soc_put_volsw_s8, \
+       .private_value = (reg) | (((signed char)max) << 16) | \
+                        (((signed char)min) << 24) }
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
 {      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
        .mask = xmask, .texts = xtexts }
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmask, xinvert,\
+        xhandler_get, xhandler_put, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
 #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_bool_ext, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = (unsigned long)&xenum }
 
+/*
+ * Bias levels
+ *
+ * @ON:      Bias is fully on for audio playback and capture operations.
+ * @PREPARE: Prepare for audio operations. Called before DAPM switching for
+ *           stream start and stop operations.
+ * @STANDBY: Low power standby state when no playback/capture operations are
+ *           in progress. NOTE: The transition time between STANDBY and ON
+ *           should be as fast as possible and no longer than 10ms.
+ * @OFF:     Power Off. No restrictions on transition times.
+ */
+enum snd_soc_bias_level {
+       SND_SOC_BIAS_ON,
+       SND_SOC_BIAS_PREPARE,
+       SND_SOC_BIAS_STANDBY,
+       SND_SOC_BIAS_OFF,
+};
+
 /*
  * Digital Audio Interface (DAI) types
  */
@@ -185,8 +221,7 @@ struct snd_soc_pcm_stream;
 struct snd_soc_ops;
 struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
-struct snd_soc_codec_dai;
-struct snd_soc_cpu_dai;
+struct snd_soc_dai;
 struct snd_soc_codec;
 struct snd_soc_machine_config;
 struct soc_enum;
@@ -221,6 +256,27 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
        struct snd_ac97_bus_ops *ops, int num);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
+/* Digital Audio Interface clocking API.*/
+int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+       unsigned int freq, int dir);
+
+int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
+       int div_id, int div);
+
+int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
+       int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+/* Digital Audio interface formatting */
+int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
+
+int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
+       unsigned int mask, int slots);
+
+int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
+
+/* Digital Audio Interface mute */
+int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
+
 /*
  *Controls
  */
@@ -249,6 +305,12 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol);
 
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
@@ -272,87 +334,45 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-/* ASoC codec DAI ops */
-struct snd_soc_codec_ops {
-       /* codec DAI clocking configuration */
-       int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
+/* ASoC DAI ops */
+struct snd_soc_dai_ops {
+       /* DAI clocking configuration */
+       int (*set_sysclk)(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir);
-       int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
+       int (*set_pll)(struct snd_soc_dai *dai,
                int pll_id, unsigned int freq_in, unsigned int freq_out);
-       int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
-               int div_id, int div);
+       int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
 
-       /* CPU DAI format configuration */
-       int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
-               unsigned int fmt);
-       int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
+       /* DAI format configuration */
+       int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
+       int (*set_tdm_slot)(struct snd_soc_dai *dai,
                unsigned int mask, int slots);
-       int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
+       int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
 
        /* digital mute */
-       int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
-};
-
-/* ASoC cpu DAI ops */
-struct snd_soc_cpu_ops {
-       /* CPU DAI clocking configuration */
-       int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
-               int clk_id, unsigned int freq, int dir);
-       int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
-               int div_id, int div);
-       int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
-               int pll_id, unsigned int freq_in, unsigned int freq_out);
-
-       /* CPU DAI format configuration */
-       int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
-               unsigned int fmt);
-       int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
-               unsigned int mask, int slots);
-       int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
-};
-
-/* SoC Codec DAI */
-struct snd_soc_codec_dai {
-       char *name;
-       int id;
-       unsigned char type;
-
-       /* DAI capabilities */
-       struct snd_soc_pcm_stream playback;
-       struct snd_soc_pcm_stream capture;
-
-       /* DAI runtime info */
-       struct snd_soc_codec *codec;
-       unsigned int active;
-       unsigned char pop_wait:1;
-
-       /* ops */
-       struct snd_soc_ops ops;
-       struct snd_soc_codec_ops dai_ops;
-
-       /* DAI private data */
-       void *private_data;
+       int (*digital_mute)(struct snd_soc_dai *dai, int mute);
 };
 
-/* SoC CPU DAI */
-struct snd_soc_cpu_dai {
-
+/* SoC  DAI (Digital Audio Interface) */
+struct snd_soc_dai {
        /* DAI description */
        char *name;
        unsigned int id;
        unsigned char type;
 
        /* DAI callbacks */
-       int (*probe)(struct platform_device *pdev);
-       void (*remove)(struct platform_device *pdev);
+       int (*probe)(struct platform_device *pdev,
+                    struct snd_soc_dai *dai);
+       void (*remove)(struct platform_device *pdev,
+                      struct snd_soc_dai *dai);
        int (*suspend)(struct platform_device *pdev,
-               struct snd_soc_cpu_dai *cpu_dai);
+               struct snd_soc_dai *dai);
        int (*resume)(struct platform_device *pdev,
-               struct snd_soc_cpu_dai *cpu_dai);
+               struct snd_soc_dai *dai);
 
        /* ops */
        struct snd_soc_ops ops;
-       struct snd_soc_cpu_ops dai_ops;
+       struct snd_soc_dai_ops dai_ops;
 
        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
@@ -360,7 +380,9 @@ struct snd_soc_cpu_dai {
 
        /* DAI runtime info */
        struct snd_pcm_runtime *runtime;
-       unsigned char active:1;
+       struct snd_soc_codec *codec;
+       unsigned int active;
+       unsigned char pop_wait:1;
        void *dma_data;
 
        /* DAI private data */
@@ -374,7 +396,8 @@ struct snd_soc_codec {
        struct mutex mutex;
 
        /* callbacks */
-       int (*dapm_event)(struct snd_soc_codec *codec, int event);
+       int (*set_bias_level)(struct snd_soc_codec *,
+                             enum snd_soc_bias_level level);
 
        /* runtime */
        struct snd_card *card;
@@ -396,12 +419,12 @@ struct snd_soc_codec {
        /* dapm */
        struct list_head dapm_widgets;
        struct list_head dapm_paths;
-       unsigned int dapm_state;
-       unsigned int suspend_dapm_state;
+       enum snd_soc_bias_level bias_level;
+       enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
 
        /* codec DAI's */
-       struct snd_soc_codec_dai *dai;
+       struct snd_soc_dai *dai;
        unsigned int num_dai;
 };
 
@@ -420,12 +443,12 @@ struct snd_soc_platform {
        int (*probe)(struct platform_device *pdev);
        int (*remove)(struct platform_device *pdev);
        int (*suspend)(struct platform_device *pdev,
-               struct snd_soc_cpu_dai *cpu_dai);
+               struct snd_soc_dai *dai);
        int (*resume)(struct platform_device *pdev,
-               struct snd_soc_cpu_dai *cpu_dai);
+               struct snd_soc_dai *dai);
 
        /* pcm creation and destruction */
-       int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
+       int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
                struct snd_pcm *);
        void (*pcm_free)(struct snd_pcm *);
 
@@ -439,8 +462,8 @@ struct snd_soc_dai_link  {
        char *stream_name;              /* Stream name */
 
        /* DAI */
-       struct snd_soc_codec_dai *codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai;
 
        /* machine stream operations */
        struct snd_soc_ops *ops;
@@ -467,7 +490,8 @@ struct snd_soc_machine {
        int (*resume_post)(struct platform_device *pdev);
 
        /* callbacks */
-       int (*dapm_event)(struct snd_soc_machine *, int event);
+       int (*set_bias_level)(struct snd_soc_machine *,
+                             enum snd_soc_bias_level level);
 
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;
@@ -482,6 +506,7 @@ struct snd_soc_device {
        struct snd_soc_codec *codec;
        struct snd_soc_codec_device *codec_dev;
        struct delayed_work delayed_work;
+       struct work_struct deferred_resume_work;
        void *codec_data;
 };
 
index 2e564bfb37fea135053d7993991b0d53e31597bd..110d5dc3a2bed878815abc5abf3c03a17a31e43e 100644 (file)
@@ -15,8 +15,6 @@
  *                           features support
  */
 
-/* $Id: uda1341.h,v 1.8 2005/11/17 14:17:21 tiwai Exp $ */
-
 #define UDA1341_ALSA_NAME "snd-uda1341"
 
 /*
index ed6fb2eb1eac210d8812bfe26016ff9dd2bbeab0..6b78aff273a8a812fd303baa7b2f7f2bae1ca969 100644 (file)
@@ -1,3 +1,3 @@
-/* include/version.h.  Generated by alsa/ksync script.  */
-#define CONFIG_SND_VERSION "1.0.16"
+/* include/version.h */
+#define CONFIG_SND_VERSION "1.0.17"
 #define CONFIG_SND_DATE ""
index acd8e062c85f381b5520c2ac27f13681053bedd0..67c4436554a9b3e80c457cd6c67437604e1613d2 100644 (file)
@@ -32,6 +32,7 @@ void unbind_from_irqhandler(unsigned int irq, void *dev_id);
 
 void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
 int resend_irq_on_evtchn(unsigned int irq);
+void rebind_evtchn_irq(int evtchn, int irq);
 
 static inline void notify_remote_via_evtchn(int port)
 {
@@ -40,4 +41,7 @@ static inline void notify_remote_via_evtchn(int port)
 }
 
 extern void notify_remote_via_irq(int irq);
+
+extern void xen_irq_resume(void);
+
 #endif /* _XEN_EVENTS_H */
index 466204846121541fe4192131cf4142c315c8f19a..a40f1cd91be1c6ad2fa7ad431b4d599c415448c1 100644 (file)
@@ -51,6 +51,9 @@ struct gnttab_free_callback {
        u16 count;
 };
 
+int gnttab_suspend(void);
+int gnttab_resume(void);
+
 int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
                                int readonly);
 
index 21c0ecfd786d7a399994838252c99f7fdc6b99c3..98b79bc404ddef529acbab64a6588c1c5998afc5 100644 (file)
@@ -3,4 +3,13 @@
 
 extern struct console xenboot_console;
 
+#ifdef CONFIG_HVC_XEN
+void xen_console_resume(void);
+#else
+static inline void xen_console_resume(void) { }
+#endif
+
+void xen_raw_console_write(const char *str);
+void xen_raw_printk(const char *fmt, ...);
+
 #endif /* XEN_HVC_CONSOLE_H */
index a64d3df5bd95abe9ab76a8d4d93a7e56d7e44d2b..7a8262c375cc874f29aecf800f0a6820039060df 100644 (file)
  */
 #define XEN_ELFNOTE_BSD_SYMTAB    11
 
+/*
+ * The lowest address the hypervisor hole can begin at (numeric).
+ *
+ * This must not be set higher than HYPERVISOR_VIRT_START. Its presence
+ * also indicates to the hypervisor that the kernel can deal with the
+ * hole starting at a higher address.
+ */
+#define XEN_ELFNOTE_HV_START_LOW  12
+
+/*
+ * List of maddr_t-sized mask/value pairs describing how to recognize
+ * (non-present) L1 page table entries carrying valid MFNs (numeric).
+ */
+#define XEN_ELFNOTE_L1_MFN_VALID  13
+
+/*
+ * Whether or not the guest supports cooperative suspend cancellation.
+ */
+#define XEN_ELFNOTE_SUSPEND_CANCEL 14
+
 #endif /* __XEN_PUBLIC_ELFNOTE_H__ */
 
 /*
index d73228d164883c494fb778a47d7e231dc5ec7bcd..f51b6413b05469abab7724717b465f7277137612 100644 (file)
@@ -38,6 +38,9 @@
  */
 #define XENFEAT_pae_pgdir_above_4gb        4
 
+/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
+#define XENFEAT_mmu_pt_update_preserve_ad  5
+
 #define XENFEAT_NR_SUBMAPS 1
 
 #endif /* __XEN_PUBLIC_FEATURES_H__ */
index 5a934dd7796dcb66fe50ffffe7db65a9fdaaf86a..974a51ed91654f39dc58a3664312642f0cfd369d 100644 (file)
@@ -49,11 +49,27 @@ struct xenfb_update {
        int32_t height;         /* rect height */
 };
 
+/*
+ * Framebuffer resize notification event
+ * Capable backend sets feature-resize in xenstore.
+ */
+#define XENFB_TYPE_RESIZE 3
+
+struct xenfb_resize {
+       uint8_t type;           /* XENFB_TYPE_RESIZE */
+       int32_t width;          /* width in pixels */
+       int32_t height;         /* height in pixels */
+       int32_t stride;         /* stride in bytes */
+       int32_t depth;          /* depth in bits */
+       int32_t offset;         /* start offset within framebuffer */
+};
+
 #define XENFB_OUT_EVENT_SIZE 40
 
 union xenfb_out_event {
        uint8_t type;
        struct xenfb_update update;
+       struct xenfb_resize resize;
        char pad[XENFB_OUT_EVENT_SIZE];
 };
 
@@ -105,15 +121,18 @@ struct xenfb_page {
         * Each directory page holds PAGE_SIZE / sizeof(*pd)
         * framebuffer pages, and can thus map up to PAGE_SIZE *
         * PAGE_SIZE / sizeof(*pd) bytes.  With PAGE_SIZE == 4096 and
-        * sizeof(unsigned long) == 4, that's 4 Megs.  Two directory
-        * pages should be enough for a while.
+        * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2
+        * Megs 64 bit.  256 directories give enough room for a 512
+        * Meg framebuffer with a max resolution of 12,800x10,240.
+        * Should be enough for a while with room leftover for
+        * expansion.
         */
-       unsigned long pd[2];
+       unsigned long pd[256];
 };
 
 /*
- * Wart: xenkbd needs to know resolution.  Put it here until a better
- * solution is found, but don't leak it to the backend.
+ * Wart: xenkbd needs to know default resolution.  Put it here until a
+ * better solution is found, but don't leak it to the backend.
  */
 #ifdef __KERNEL__
 #define XENFB_WIDTH 800
index fb97f4284ffd37d2233eabf9b2776bc5938533bf..8066c7849fbee36b8d8b0544281fc33af802db96 100644 (file)
@@ -49,6 +49,7 @@ struct xenkbd_motion {
        uint8_t type;           /* XENKBD_TYPE_MOTION */
        int32_t rel_x;          /* relative X motion */
        int32_t rel_y;          /* relative Y motion */
+       int32_t rel_z;          /* relative Z motion (wheel) */
 };
 
 struct xenkbd_key {
@@ -61,6 +62,7 @@ struct xenkbd_position {
        uint8_t type;           /* XENKBD_TYPE_POS */
        int32_t abs_x;          /* absolute X position (in FB pixels) */
        int32_t abs_y;          /* absolute Y position (in FB pixels) */
+       int32_t rel_z;          /* relative Z motion (wheel) */
 };
 
 #define XENKBD_IN_EVENT_SIZE 40
index da768469aa92b1a3cd948fc5f03f3cf0bd69751d..af36ead168170c1ded3819d523318490342d848e 100644 (file)
@@ -29,7 +29,7 @@ struct xen_memory_reservation {
      *   OUT: GMFN bases of extents that were allocated
      *   (NB. This command also updates the mach_to_phys translation table)
      */
-    ulong extent_start;
+    GUEST_HANDLE(ulong) extent_start;
 
     /* Number of extents, and size/alignment of each (2^extent_order pages). */
     unsigned long  nr_extents;
@@ -50,6 +50,7 @@ struct xen_memory_reservation {
     domid_t        domid;
 
 };
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
 
 /*
  * Returns the maximum machine frame number of mapped RAM in this system.
@@ -85,7 +86,7 @@ struct xen_machphys_mfn_list {
      * any large discontiguities in the machine address space, 2MB gaps in
      * the machphys table will be represented by an MFN base of zero.
      */
-    ulong extent_start;
+    GUEST_HANDLE(ulong) extent_start;
 
     /*
      * Number of extents written to the above array. This will be smaller
@@ -93,6 +94,7 @@ struct xen_machphys_mfn_list {
      */
     unsigned int nr_extents;
 };
+DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
 
 /*
  * Sets the GPFN at which a particular page appears in the specified guest's
@@ -115,6 +117,7 @@ struct xen_add_to_physmap {
     /* GPFN where the source mapping page should appear. */
     unsigned long gpfn;
 };
+DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap);
 
 /*
  * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
@@ -129,13 +132,14 @@ struct xen_translate_gpfn_list {
     unsigned long nr_gpfns;
 
     /* List of GPFNs to translate. */
-    ulong gpfn_list;
+    GUEST_HANDLE(ulong) gpfn_list;
 
     /*
      * Output list to contain MFN translations. May be the same as the input
      * list (in which case each input GPFN is overwritten with the output MFN).
      */
-    ulong mfn_list;
+    GUEST_HANDLE(ulong) mfn_list;
 };
+DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
 
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
index 819a0331cda9d440fd368f16d38941db371caa8c..2befa3e2f1bce59edaddfb25ce1b301aa6e554e3 100644 (file)
  * ptr[:2]  -- Machine address within the frame whose mapping to modify.
  *             The frame must belong to the FD, if one is specified.
  * val      -- Value to write into the mapping entry.
+ *
+ * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD:
+ * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed
+ * with those in @val.
  */
-#define MMU_NORMAL_PT_UPDATE     0 /* checked '*ptr = val'. ptr is MA.       */
-#define MMU_MACHPHYS_UPDATE      1 /* ptr = MA of frame to modify entry for  */
+#define MMU_NORMAL_PT_UPDATE      0 /* checked '*ptr = val'. ptr is MA.       */
+#define MMU_MACHPHYS_UPDATE       1 /* ptr = MA of frame to modify entry for  */
+#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */
 
 /*
  * MMU EXTENDED OPERATIONS
index 10ddfe0142d08e93be872477025168eb4e0dab47..a706d6a7896016c8698698ad1472a26b7551cab9 100644 (file)
@@ -5,4 +5,10 @@
 
 DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
 
+void xen_pre_suspend(void);
+void xen_post_suspend(int suspend_cancelled);
+
+void xen_mm_pin_all(void);
+void xen_mm_unpin_all(void);
+
 #endif /* INCLUDE_XEN_OPS_H */
index ecb3822d4f70ed177c45318c31aeaf8f58b1273a..7963e3fc51d9c8a60550c934210b987e375a0860 100644 (file)
@@ -8,7 +8,9 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/timex.h>
+#include <linux/smp.h>
 
+unsigned long lpj_fine;
 unsigned long preset_lpj;
 static int __init lpj_setup(char *str)
 {
@@ -33,9 +35,9 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
        unsigned long pre_start, start, post_start;
        unsigned long pre_end, end, post_end;
        unsigned long start_jiffies;
-       unsigned long tsc_rate_min, tsc_rate_max;
-       unsigned long good_tsc_sum = 0;
-       unsigned long good_tsc_count = 0;
+       unsigned long timer_rate_min, timer_rate_max;
+       unsigned long good_timer_sum = 0;
+       unsigned long good_timer_count = 0;
        int i;
 
        if (read_current_timer(&pre_start) < 0 )
@@ -79,22 +81,24 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
                }
                read_current_timer(&post_end);
 
-               tsc_rate_max = (post_end - pre_start) / DELAY_CALIBRATION_TICKS;
-               tsc_rate_min = (pre_end - post_start) / DELAY_CALIBRATION_TICKS;
+               timer_rate_max = (post_end - pre_start) /
+                                       DELAY_CALIBRATION_TICKS;
+               timer_rate_min = (pre_end - post_start) /
+                                       DELAY_CALIBRATION_TICKS;
 
                /*
-                * If the upper limit and lower limit of the tsc_rate is
+                * If the upper limit and lower limit of the timer_rate is
                 * >= 12.5% apart, redo calibration.
                 */
                if (pre_start != 0 && pre_end != 0 &&
-                   (tsc_rate_max - tsc_rate_min) < (tsc_rate_max >> 3)) {
-                       good_tsc_count++;
-                       good_tsc_sum += tsc_rate_max;
+                   (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) {
+                       good_timer_count++;
+                       good_timer_sum += timer_rate_max;
                }
        }
 
-       if (good_tsc_count)
-               return (good_tsc_sum/good_tsc_count);
+       if (good_timer_count)
+               return (good_timer_sum/good_timer_count);
 
        printk(KERN_WARNING "calibrate_delay_direct() failed to get a good "
               "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n");
@@ -108,6 +112,10 @@ static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
  * This is the number of bits of precision for the loops_per_jiffy.  Each
  * bit takes on average 1.5/HZ seconds.  This (like the original) is a little
  * better than 1%
+ * For the boot cpu we can skip the delay calibration and assign it a value
+ * calculated based on the timer frequency.
+ * For the rest of the CPUs we cannot assume that the timer frequency is same as
+ * the cpu frequency, hence do the calibration for those.
  */
 #define LPS_PREC 8
 
@@ -118,20 +126,20 @@ void __cpuinit calibrate_delay(void)
 
        if (preset_lpj) {
                loops_per_jiffy = preset_lpj;
-               printk("Calibrating delay loop (skipped)... "
-                       "%lu.%02lu BogoMIPS preset\n",
-                       loops_per_jiffy/(500000/HZ),
-                       (loops_per_jiffy/(5000/HZ)) % 100);
+               printk(KERN_INFO
+                       "Calibrating delay loop (skipped) preset value.. ");
+       } else if ((smp_processor_id() == 0) && lpj_fine) {
+               loops_per_jiffy = lpj_fine;
+               printk(KERN_INFO
+                       "Calibrating delay loop (skipped), "
+                       "value calculated using timer frequency.. ");
        } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
-               printk("Calibrating delay using timer specific routine.. ");
-               printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
-                       loops_per_jiffy/(500000/HZ),
-                       (loops_per_jiffy/(5000/HZ)) % 100,
-                       loops_per_jiffy);
+               printk(KERN_INFO
+                       "Calibrating delay using timer specific routine.. ");
        } else {
                loops_per_jiffy = (1<<12);
 
-               printk(KERN_DEBUG "Calibrating delay loop... ");
+               printk(KERN_INFO "Calibrating delay loop... ");
                while ((loops_per_jiffy <<= 1) != 0) {
                        /* wait for "start of" clock tick */
                        ticks = jiffies;
@@ -161,12 +169,8 @@ void __cpuinit calibrate_delay(void)
                        if (jiffies != ticks)   /* longer than 1 tick */
                                loops_per_jiffy &= ~loopbit;
                }
-
-               /* Round the value and print it */
-               printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
-                       loops_per_jiffy/(500000/HZ),
-                       (loops_per_jiffy/(5000/HZ)) % 100,
-                       loops_per_jiffy);
        }
-
+       printk(KERN_INFO "%lu.%02lu BogoMIPS (lpj=%lu)\n",
+                       loops_per_jiffy/(500000/HZ),
+                       (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
 }
index 8f6185e69b691265746f81a1ca4ce9de9fd8a640..ceb258782835a1073774e0337e0bc4d85f7a160f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/personality.h>
 #include <linux/tty.h>
 #include <linux/mnt_namespace.h>
+#include <linux/iocontext.h>
 #include <linux/key.h>
 #include <linux/security.h>
 #include <linux/cpu.h>
index 19908b26cf80494a0db8f3410384521081293a32..b71ccd09fc8def0bb524d536b9faf3fee8e50451 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sem.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/iocontext.h>
 #include <linux/key.h>
 #include <linux/binfmts.h>
 #include <linux/mman.h>
index e2129e83fd75b8d0c708a7c410005015e0cba564..625d240d7ada4633de19e99659d481af68b59913 100644 (file)
@@ -75,6 +75,8 @@ EXPORT_SYMBOL(oops_in_progress);
 static DECLARE_MUTEX(console_sem);
 static DECLARE_MUTEX(secondary_console_sem);
 struct console *console_drivers;
+EXPORT_SYMBOL_GPL(console_drivers);
+
 /*
  * This is used for debugging the mess that is the VT code by
  * keeping track if we have the console semaphore held. It's
@@ -121,6 +123,8 @@ struct console_cmdline
 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
 static int selected_console = -1;
 static int preferred_console = -1;
+int console_set_on_cmdline;
+EXPORT_SYMBOL(console_set_on_cmdline);
 
 /* Flag: console code may call schedule() */
 static int console_may_schedule;
@@ -890,6 +894,7 @@ static int __init console_setup(char *str)
        *s = 0;
 
        __add_preferred_console(buf, idx, options, brl_options);
+       console_set_on_cmdline = 1;
        return 1;
 }
 __setup("console=", console_setup);
index 6c19e94fd0a5482786e432599a0fb4840a5c66cb..e337390fce011dc0ea1d5eba1cf678553fb93b71 100644 (file)
@@ -121,7 +121,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
        return ret;
 }
 
-int __ptrace_may_attach(struct task_struct *task)
+int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        /* May we inspect the given task?
         * This check is used both for attaching with ptrace
@@ -148,16 +148,16 @@ int __ptrace_may_attach(struct task_struct *task)
        if (!dumpable && !capable(CAP_SYS_PTRACE))
                return -EPERM;
 
-       return security_ptrace(current, task);
+       return security_ptrace(current, task, mode);
 }
 
-int ptrace_may_attach(struct task_struct *task)
+bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        int err;
        task_lock(task);
-       err = __ptrace_may_attach(task);
+       err = __ptrace_may_access(task, mode);
        task_unlock(task);
-       return !err;
+       return (!err ? true : false);
 }
 
 int ptrace_attach(struct task_struct *task)
@@ -195,7 +195,7 @@ repeat:
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;
-       retval = __ptrace_may_attach(task);
+       retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
        if (retval)
                goto bad;
 
@@ -494,7 +494,8 @@ int ptrace_traceme(void)
         */
        task_lock(current);
        if (!(current->ptrace & PT_PTRACED)) {
-               ret = security_ptrace(current->parent, current);
+               ret = security_ptrace(current->parent, current,
+                                     PTRACE_MODE_ATTACH);
                /*
                 * Set the ptrace bit in the process ptrace flags.
                 */
index d16c8d9fbd8bbed949f2f91024f07688e76fcb43..591d5e7f757ad7438e9696bd3735f4b098dfda92 100644 (file)
@@ -6774,9 +6774,9 @@ static int find_next_best_node(int node, nodemask_t *used_nodes)
 
        min_val = INT_MAX;
 
-       for (i = 0; i < MAX_NUMNODES; i++) {
+       for (i = 0; i < nr_node_ids; i++) {
                /* Start at @node */
-               n = (node + i) % MAX_NUMNODES;
+               n = (node + i) % nr_node_ids;
 
                if (!nr_cpus_node(n))
                        continue;
@@ -6970,7 +6970,7 @@ static void free_sched_groups(const cpumask_t *cpu_map, cpumask_t *nodemask)
                if (!sched_group_nodes)
                        continue;
 
-               for (i = 0; i < MAX_NUMNODES; i++) {
+               for (i = 0; i < nr_node_ids; i++) {
                        struct sched_group *oldsg, *sg = sched_group_nodes[i];
 
                        *nodemask = node_to_cpumask(i);
@@ -7163,7 +7163,7 @@ static int __build_sched_domains(const cpumask_t *cpu_map,
        /*
         * Allocate the per-node list of sched groups
         */
-       sched_group_nodes = kcalloc(MAX_NUMNODES, sizeof(struct sched_group *),
+       sched_group_nodes = kcalloc(nr_node_ids, sizeof(struct sched_group *),
                                    GFP_KERNEL);
        if (!sched_group_nodes) {
                printk(KERN_WARNING "Can not alloc sched group node list\n");
@@ -7302,7 +7302,7 @@ static int __build_sched_domains(const cpumask_t *cpu_map,
 #endif
 
        /* Set up physical groups */
-       for (i = 0; i < MAX_NUMNODES; i++) {
+       for (i = 0; i < nr_node_ids; i++) {
                SCHED_CPUMASK_VAR(nodemask, allmasks);
                SCHED_CPUMASK_VAR(send_covered, allmasks);
 
@@ -7326,7 +7326,7 @@ static int __build_sched_domains(const cpumask_t *cpu_map,
                                        send_covered, tmpmask);
        }
 
-       for (i = 0; i < MAX_NUMNODES; i++) {
+       for (i = 0; i < nr_node_ids; i++) {
                /* Set up node groups */
                struct sched_group *sg, *prev;
                SCHED_CPUMASK_VAR(nodemask, allmasks);
@@ -7365,9 +7365,9 @@ static int __build_sched_domains(const cpumask_t *cpu_map,
                cpus_or(*covered, *covered, *nodemask);
                prev = sg;
 
-               for (j = 0; j < MAX_NUMNODES; j++) {
+               for (j = 0; j < nr_node_ids; j++) {
                        SCHED_CPUMASK_VAR(notcovered, allmasks);
-                       int n = (i + j) % MAX_NUMNODES;
+                       int n = (i + j) % nr_node_ids;
                        node_to_cpumask_ptr(pnodemask, n);
 
                        cpus_complement(*notcovered, *covered);
@@ -7420,7 +7420,7 @@ static int __build_sched_domains(const cpumask_t *cpu_map,
        }
 
 #ifdef CONFIG_NUMA
-       for (i = 0; i < MAX_NUMNODES; i++)
+       for (i = 0; i < nr_node_ids; i++)
                init_numa_sched_groups_power(sched_group_nodes[i]);
 
        if (sd_allnodes) {
index 57a1f02e5ec07fc20a6715d40d7fe41855449727..67f80c2617096454a1d0b1f520825034f7c87dfc 100644 (file)
@@ -30,6 +30,7 @@
 struct tick_device tick_broadcast_device;
 static cpumask_t tick_broadcast_mask;
 static DEFINE_SPINLOCK(tick_broadcast_lock);
+static int tick_broadcast_force;
 
 #ifdef CONFIG_TICK_ONESHOT
 static void tick_broadcast_clear_oneshot(int cpu);
@@ -232,10 +233,11 @@ static void tick_do_broadcast_on_off(void *why)
                                                     CLOCK_EVT_MODE_SHUTDOWN);
                }
                if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
-                       dev->features |= CLOCK_EVT_FEAT_DUMMY;
+                       tick_broadcast_force = 1;
                break;
        case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
-               if (cpu_isset(cpu, tick_broadcast_mask)) {
+               if (!tick_broadcast_force &&
+                   cpu_isset(cpu, tick_broadcast_mask)) {
                        cpu_clear(cpu, tick_broadcast_mask);
                        if (td->mode == TICKDEV_MODE_PERIODIC)
                                tick_setup_periodic(dev, 0);
index 3aa819d628c112cc185f9545c7ae5e3fb8a5c310..c4de85285bb43cd2ab9810d42c67c8001d9adb1b 100644 (file)
@@ -129,7 +129,7 @@ config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
        depends on SPARSEMEM || X86_64_ACPI_NUMA
        depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG
-       depends on (IA64 || X86 || PPC64 || SUPERH)
+       depends on (IA64 || X86 || PPC64 || SUPERH || S390)
 
 comment "Memory hotplug is currently incompatible with Software Suspend"
        depends on SPARSEMEM && HOTPLUG && HIBERNATION
@@ -199,7 +199,7 @@ config BOUNCE
 config NR_QUICK
        int
        depends on QUICKLIST
-       default "2" if SUPERH
+       default "2" if SUPERH || AVR32
        default "1"
 
 config VIRT_TO_BUS
index a5bf31c273757848ae7614bd9fc3c8595c493705..acfe7c8d72fcff59dec990869a5fce9d63b56e55 100644 (file)
@@ -47,19 +47,17 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
                if (pte_present(oldpte)) {
                        pte_t ptent;
 
-                       /* Avoid an SMP race with hardware updated dirty/clean
-                        * bits by wiping the pte and then setting the new pte
-                        * into place.
-                        */
-                       ptent = ptep_get_and_clear(mm, addr, pte);
+                       ptent = ptep_modify_prot_start(mm, addr, pte);
                        ptent = pte_modify(ptent, newprot);
+
                        /*
                         * Avoid taking write faults for pages we know to be
                         * dirty.
                         */
                        if (dirty_accountable && pte_dirty(ptent))
                                ptent = pte_mkwrite(ptent);
-                       set_pte_at(mm, addr, pte, ptent);
+
+                       ptep_modify_prot_commit(mm, addr, pte, ptent);
 #ifdef CONFIG_MIGRATION
                } else if (!pte_file(oldpte)) {
                        swp_entry_t entry = pte_to_swp_entry(oldpte);
index f32fae3121f07461f846911ee6963ce679828780..f024b9b3a2a6d1ea9d455a1e0e019391e57a606d 100644 (file)
@@ -2929,6 +2929,18 @@ void __init free_bootmem_with_active_regions(int nid,
        }
 }
 
+void __init work_with_active_regions(int nid, work_fn_t work_fn, void *data)
+{
+       int i;
+       int ret;
+
+       for_each_active_range_index_in_nid(i, nid) {
+               ret = work_fn(early_node_map[i].start_pfn,
+                             early_node_map[i].end_pfn, data);
+               if (ret)
+                       break;
+       }
+}
 /**
  * sparse_memory_present_with_active_regions - Call memory_present for each active range
  * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used.
@@ -3461,6 +3473,11 @@ void __paginginit free_area_init_node(int nid, struct pglist_data *pgdat,
        calculate_node_totalpages(pgdat, zones_size, zholes_size);
 
        alloc_node_mem_map(pgdat);
+#ifdef CONFIG_FLAT_NODE_MEM_MAP
+       printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n",
+               nid, (unsigned long)pgdat,
+               (unsigned long)pgdat->node_mem_map);
+#endif
 
        free_area_init_core(pgdat, zones_size, zholes_size);
 }
@@ -3503,7 +3520,7 @@ void __init add_active_range(unsigned int nid, unsigned long start_pfn,
 {
        int i;
 
-       printk(KERN_DEBUG "Entering add_active_range(%d, %lu, %lu) "
+       printk(KERN_DEBUG "Entering add_active_range(%d, %#lx, %#lx) "
                          "%d entries of %d used\n",
                          nid, start_pfn, end_pfn,
                          nr_nodemap_entries, MAX_ACTIVE_REGIONS);
@@ -3547,27 +3564,68 @@ void __init add_active_range(unsigned int nid, unsigned long start_pfn,
 }
 
 /**
- * shrink_active_range - Shrink an existing registered range of PFNs
+ * remove_active_range - Shrink an existing registered range of PFNs
  * @nid: The node id the range is on that should be shrunk
- * @old_end_pfn: The old end PFN of the range
- * @new_end_pfn: The new PFN of the range
+ * @start_pfn: The new PFN of the range
+ * @end_pfn: The new PFN of the range
  *
  * i386 with NUMA use alloc_remap() to store a node_mem_map on a local node.
- * The map is kept at the end physical page range that has already been
- * registered with add_active_range(). This function allows an arch to shrink
- * an existing registered range.
+ * The map is kept near the end physical page range that has already been
+ * registered. This function allows an arch to shrink an existing registered
+ * range.
  */
-void __init shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
-                                               unsigned long new_end_pfn)
+void __init remove_active_range(unsigned int nid, unsigned long start_pfn,
+                               unsigned long end_pfn)
 {
-       int i;
+       int i, j;
+       int removed = 0;
+
+       printk(KERN_DEBUG "remove_active_range (%d, %lu, %lu)\n",
+                         nid, start_pfn, end_pfn);
 
        /* Find the old active region end and shrink */
-       for_each_active_range_index_in_nid(i, nid)
-               if (early_node_map[i].end_pfn == old_end_pfn) {
-                       early_node_map[i].end_pfn = new_end_pfn;
-                       break;
+       for_each_active_range_index_in_nid(i, nid) {
+               if (early_node_map[i].start_pfn >= start_pfn &&
+                   early_node_map[i].end_pfn <= end_pfn) {
+                       /* clear it */
+                       early_node_map[i].start_pfn = 0;
+                       early_node_map[i].end_pfn = 0;
+                       removed = 1;
+                       continue;
+               }
+               if (early_node_map[i].start_pfn < start_pfn &&
+                   early_node_map[i].end_pfn > start_pfn) {
+                       unsigned long temp_end_pfn = early_node_map[i].end_pfn;
+                       early_node_map[i].end_pfn = start_pfn;
+                       if (temp_end_pfn > end_pfn)
+                               add_active_range(nid, end_pfn, temp_end_pfn);
+                       continue;
                }
+               if (early_node_map[i].start_pfn >= start_pfn &&
+                   early_node_map[i].end_pfn > end_pfn &&
+                   early_node_map[i].start_pfn < end_pfn) {
+                       early_node_map[i].start_pfn = end_pfn;
+                       continue;
+               }
+       }
+
+       if (!removed)
+               return;
+
+       /* remove the blank ones */
+       for (i = nr_nodemap_entries - 1; i > 0; i--) {
+               if (early_node_map[i].nid != nid)
+                       continue;
+               if (early_node_map[i].end_pfn)
+                       continue;
+               /* we found it, get rid of it */
+               for (j = i; j < nr_nodemap_entries - 1; j++)
+                       memcpy(&early_node_map[j], &early_node_map[j+1],
+                               sizeof(early_node_map[j]));
+               j = nr_nodemap_entries - 1;
+               memset(&early_node_map[j], 0, sizeof(early_node_map[j]));
+               nr_nodemap_entries--;
+       }
 }
 
 /**
@@ -3611,7 +3669,7 @@ static void __init sort_node_map(void)
 }
 
 /* Find the lowest pfn for a node */
-unsigned long __init find_min_pfn_for_node(unsigned long nid)
+unsigned long __init find_min_pfn_for_node(int nid)
 {
        int i;
        unsigned long min_pfn = ULONG_MAX;
@@ -3622,7 +3680,7 @@ unsigned long __init find_min_pfn_for_node(unsigned long nid)
 
        if (min_pfn == ULONG_MAX) {
                printk(KERN_WARNING
-                       "Could not find start_pfn for node %lu\n", nid);
+                       "Could not find start_pfn for node %d\n", nid);
                return 0;
        }
 
@@ -3878,7 +3936,7 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
        for (i = 0; i < MAX_NR_ZONES; i++) {
                if (i == ZONE_MOVABLE)
                        continue;
-               printk("  %-8s %8lu -> %8lu\n",
+               printk("  %-8s %0#10lx -> %0#10lx\n",
                                zone_names[i],
                                arch_zone_lowest_possible_pfn[i],
                                arch_zone_highest_possible_pfn[i]);
@@ -3894,7 +3952,7 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
        /* Print out the early_node_map[] */
        printk("early_node_map[%d] active PFN ranges\n", nr_nodemap_entries);
        for (i = 0; i < nr_nodemap_entries; i++)
-               printk("  %3d: %8lu -> %8lu\n", early_node_map[i].nid,
+               printk("  %3d: %0#10lx -> %0#10lx\n", early_node_map[i].nid,
                                                early_node_map[i].start_pfn,
                                                early_node_map[i].end_pfn);
 
index 315c392253c73a49212d9bf3511c08624de76099..5f6e2c4a2ba7cbf51e85961eaa56b9d3f82981f0 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -431,9 +431,8 @@ static void print_track(const char *s, struct track *t)
        if (!t->addr)
                return;
 
-       printk(KERN_ERR "INFO: %s in ", s);
-       __print_symbol("%s", (unsigned long)t->addr);
-       printk(" age=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid);
+       printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n",
+               s, t->addr, jiffies - t->when, t->cpu, t->pid);
 }
 
 static void print_tracking(struct kmem_cache *s, void *object)
index 7b0038f45b168c3aab1e2f236dd62584542c0331..bda71015885cd2fdbfb4a0135eb82445854d9e08 100644 (file)
@@ -1135,8 +1135,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
                if (this)
                        kfree_skb(this);
        }
-       if (!this)
-               printk(KERN_ERR "AF_IUCV msg tag %u not found\n", msg->tag);
+       BUG_ON(!this);
 
        if (sk->sk_state == IUCV_CLOSING) {
                if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
@@ -1196,7 +1195,7 @@ static int __init afiucv_init(void)
        }
        cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err);
        if (unlikely(err)) {
-               printk(KERN_ERR "AF_IUCV needs the VM userid\n");
+               WARN_ON(err);
                err = -EPROTONOSUPPORT;
                goto out;
        }
@@ -1210,7 +1209,6 @@ static int __init afiucv_init(void)
        err = sock_register(&iucv_sock_family_ops);
        if (err)
                goto out_proto;
-       printk(KERN_INFO "AF_IUCV lowlevel driver initialized\n");
        return 0;
 
 out_proto:
@@ -1226,8 +1224,6 @@ static void __exit afiucv_exit(void)
        sock_unregister(PF_IUCV);
        proto_unregister(&iucv_proto);
        iucv_unregister(&af_iucv_handler, 0);
-
-       printk(KERN_INFO "AF_IUCV lowlevel driver unloaded\n");
 }
 
 module_init(afiucv_init);
index 91897076213158bbad89db5f8cacc1b2b49acc74..7f82b7616212eeaa6ab04fab033510ba9b39fb8f 100644 (file)
@@ -1559,16 +1559,11 @@ static void iucv_external_interrupt(u16 code)
 
        p = iucv_irq_data[smp_processor_id()];
        if (p->ippathid >= iucv_max_pathid) {
-               printk(KERN_WARNING "iucv_do_int: Got interrupt with "
-                      "pathid %d > max_connections (%ld)\n",
-                      p->ippathid, iucv_max_pathid - 1);
+               WARN_ON(p->ippathid >= iucv_max_pathid);
                iucv_sever_pathid(p->ippathid, iucv_error_no_listener);
                return;
        }
-       if (p->iptype  < 0x01 || p->iptype > 0x09) {
-               printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n");
-               return;
-       }
+       BUG_ON(p->iptype  < 0x01 || p->iptype > 0x09);
        work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);
        if (!work) {
                printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");
index cea4a790e1e97170459576b8b68c94daf3e95cc9..37d5c363fbcd8f0008044a08414721f9710c7442 100644 (file)
@@ -304,6 +304,14 @@ static int do_ap_entry(const char *filename,
        return 1;
 }
 
+/* looks like: "css:tN" */
+static int do_css_entry(const char *filename,
+                       struct css_device_id *id, char *alias)
+{
+       sprintf(alias, "css:t%01X", id->type);
+       return 1;
+}
+
 /* Looks like: "serio:tyNprNidNexN" */
 static int do_serio_entry(const char *filename,
                          struct serio_device_id *id, char *alias)
@@ -680,6 +688,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct ap_device_id), "ap",
                         do_ap_entry, mod);
+       else if (sym_is(symname, "__mod_css_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct css_device_id), "css",
+                        do_css_entry, mod);
        else if (sym_is(symname, "__mod_serio_device_table"))
                do_table(symval, sym->st_size,
                         sizeof(struct serio_device_id), "serio",
index 49b51f964897dcb7133be9b58f1b936462bb6309..62ed4717d334f3f10de514aa4b9e088f4b2ca827 100644 (file)
@@ -73,17 +73,9 @@ config SECURITY_NETWORK_XFRM
          IPSec.
          If you are unsure how to answer this question, answer N.
 
-config SECURITY_CAPABILITIES
-       bool "Default Linux Capabilities"
-       depends on SECURITY
-       default y
-       help
-         This enables the "default" Linux capabilities functionality.
-         If you are unsure how to answer this question, answer Y.
-
 config SECURITY_FILE_CAPABILITIES
        bool "File POSIX Capabilities (EXPERIMENTAL)"
-       depends on (SECURITY=n || SECURITY_CAPABILITIES!=n) && EXPERIMENTAL
+       depends on EXPERIMENTAL
        default n
        help
          This enables filesystem capabilities, allowing you to give
index 7ef1107a72875412e3cdc52f48fe609f7dfbc764..f65426099aa625be9aac60a1a009ea860956dbb7 100644 (file)
@@ -6,16 +6,13 @@ obj-$(CONFIG_KEYS)                    += keys/
 subdir-$(CONFIG_SECURITY_SELINUX)      += selinux
 subdir-$(CONFIG_SECURITY_SMACK)                += smack
 
-# if we don't select a security model, use the default capabilities
-ifneq ($(CONFIG_SECURITY),y)
+# always enable default capabilities
 obj-y          += commoncap.o
-endif
 
 # Object file lists
-obj-$(CONFIG_SECURITY)                 += security.o dummy.o inode.o
+obj-$(CONFIG_SECURITY)                 += security.o capability.o inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
-obj-$(CONFIG_SECURITY_SMACK)           += commoncap.o smack/built-in.o
-obj-$(CONFIG_SECURITY_CAPABILITIES)    += commoncap.o capability.o
-obj-$(CONFIG_SECURITY_ROOTPLUG)                += commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
+obj-$(CONFIG_SECURITY_ROOTPLUG)                += root_plug.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
index 38ac54e3aed14aebfe84f0b8e11ce4802dae845c..5b01c0b02422b28a1809ba7be383e1b93e76159f 100644 (file)
@@ -1,6 +1,8 @@
 /*
  *  Capabilities Linux Security Module
  *
+ *  This is the default security module in case no other module is loaded.
+ *
  *     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
  *
  */
 
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/security.h>
-#include <linux/file.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <linux/ptrace.h>
-#include <linux/moduleparam.h>
-
-static struct security_operations capability_ops = {
-       .ptrace =                       cap_ptrace,
-       .capget =                       cap_capget,
-       .capset_check =                 cap_capset_check,
-       .capset_set =                   cap_capset_set,
-       .capable =                      cap_capable,
-       .settime =                      cap_settime,
-       .netlink_send =                 cap_netlink_send,
-       .netlink_recv =                 cap_netlink_recv,
-
-       .bprm_apply_creds =             cap_bprm_apply_creds,
-       .bprm_set_security =            cap_bprm_set_security,
-       .bprm_secureexec =              cap_bprm_secureexec,
-
-       .inode_setxattr =               cap_inode_setxattr,
-       .inode_removexattr =            cap_inode_removexattr,
-       .inode_need_killpriv =          cap_inode_need_killpriv,
-       .inode_killpriv =               cap_inode_killpriv,
-
-       .task_setscheduler =            cap_task_setscheduler,
-       .task_setioprio =               cap_task_setioprio,
-       .task_setnice =                 cap_task_setnice,
-       .task_post_setuid =             cap_task_post_setuid,
-       .task_prctl =                   cap_task_prctl,
-       .task_reparent_to_init =        cap_task_reparent_to_init,
-
-       .syslog =                       cap_syslog,
-
-       .vm_enough_memory =             cap_vm_enough_memory,
-};
 
-/* flag to keep track of how we were registered */
-static int secondary;
+static int cap_acct(struct file *file)
+{
+       return 0;
+}
+
+static int cap_sysctl(ctl_table *table, int op)
+{
+       return 0;
+}
+
+static int cap_quotactl(int cmds, int type, int id, struct super_block *sb)
+{
+       return 0;
+}
+
+static int cap_quota_on(struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_bprm_alloc_security(struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static void cap_bprm_free_security(struct linux_binprm *bprm)
+{
+}
+
+static void cap_bprm_post_apply_creds(struct linux_binprm *bprm)
+{
+}
+
+static int cap_bprm_check_security(struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static int cap_sb_alloc_security(struct super_block *sb)
+{
+       return 0;
+}
+
+static void cap_sb_free_security(struct super_block *sb)
+{
+}
+
+static int cap_sb_copy_data(char *orig, char *copy)
+{
+       return 0;
+}
+
+static int cap_sb_kern_mount(struct super_block *sb, void *data)
+{
+       return 0;
+}
+
+static int cap_sb_show_options(struct seq_file *m, struct super_block *sb)
+{
+       return 0;
+}
+
+static int cap_sb_statfs(struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_sb_mount(char *dev_name, struct path *path, char *type,
+                       unsigned long flags, void *data)
+{
+       return 0;
+}
+
+static int cap_sb_check_sb(struct vfsmount *mnt, struct path *path)
+{
+       return 0;
+}
+
+static int cap_sb_umount(struct vfsmount *mnt, int flags)
+{
+       return 0;
+}
+
+static void cap_sb_umount_close(struct vfsmount *mnt)
+{
+}
+
+static void cap_sb_umount_busy(struct vfsmount *mnt)
+{
+}
+
+static void cap_sb_post_remount(struct vfsmount *mnt, unsigned long flags,
+                               void *data)
+{
+}
+
+static void cap_sb_post_addmount(struct vfsmount *mnt, struct path *path)
+{
+}
+
+static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
+{
+       return 0;
+}
+
+static void cap_sb_post_pivotroot(struct path *old_path, struct path *new_path)
+{
+}
+
+static int cap_sb_set_mnt_opts(struct super_block *sb,
+                              struct security_mnt_opts *opts)
+{
+       if (unlikely(opts->num_mnt_opts))
+               return -EOPNOTSUPP;
+       return 0;
+}
+
+static void cap_sb_clone_mnt_opts(const struct super_block *oldsb,
+                                 struct super_block *newsb)
+{
+}
+
+static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
+{
+       return 0;
+}
+
+static int cap_inode_alloc_security(struct inode *inode)
+{
+       return 0;
+}
+
+static void cap_inode_free_security(struct inode *inode)
+{
+}
+
+static int cap_inode_init_security(struct inode *inode, struct inode *dir,
+                                  char **name, void **value, size_t *len)
+{
+       return -EOPNOTSUPP;
+}
+
+static int cap_inode_create(struct inode *inode, struct dentry *dentry,
+                           int mask)
+{
+       return 0;
+}
+
+static int cap_inode_link(struct dentry *old_dentry, struct inode *inode,
+                         struct dentry *new_dentry)
+{
+       return 0;
+}
+
+static int cap_inode_unlink(struct inode *inode, struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_inode_symlink(struct inode *inode, struct dentry *dentry,
+                            const char *name)
+{
+       return 0;
+}
+
+static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry,
+                          int mask)
+{
+       return 0;
+}
+
+static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_inode_mknod(struct inode *inode, struct dentry *dentry,
+                          int mode, dev_t dev)
+{
+       return 0;
+}
+
+static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
+                           struct inode *new_inode, struct dentry *new_dentry)
+{
+       return 0;
+}
+
+static int cap_inode_readlink(struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_inode_follow_link(struct dentry *dentry,
+                                struct nameidata *nameidata)
+{
+       return 0;
+}
+
+static int cap_inode_permission(struct inode *inode, int mask,
+                               struct nameidata *nd)
+{
+       return 0;
+}
+
+static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       return 0;
+}
+
+static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+       return 0;
+}
+
+static void cap_inode_delete(struct inode *ino)
+{
+}
+
+static void cap_inode_post_setxattr(struct dentry *dentry, const char *name,
+                                   const void *value, size_t size, int flags)
+{
+}
+
+static int cap_inode_getxattr(struct dentry *dentry, const char *name)
+{
+       return 0;
+}
+
+static int cap_inode_listxattr(struct dentry *dentry)
+{
+       return 0;
+}
+
+static int cap_inode_getsecurity(const struct inode *inode, const char *name,
+                                void **buffer, bool alloc)
+{
+       return -EOPNOTSUPP;
+}
+
+static int cap_inode_setsecurity(struct inode *inode, const char *name,
+                                const void *value, size_t size, int flags)
+{
+       return -EOPNOTSUPP;
+}
+
+static int cap_inode_listsecurity(struct inode *inode, char *buffer,
+                                 size_t buffer_size)
+{
+       return 0;
+}
+
+static void cap_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+       *secid = 0;
+}
+
+static int cap_file_permission(struct file *file, int mask)
+{
+       return 0;
+}
+
+static int cap_file_alloc_security(struct file *file)
+{
+       return 0;
+}
+
+static void cap_file_free_security(struct file *file)
+{
+}
+
+static int cap_file_ioctl(struct file *file, unsigned int command,
+                         unsigned long arg)
+{
+       return 0;
+}
+
+static int cap_file_mmap(struct file *file, unsigned long reqprot,
+                        unsigned long prot, unsigned long flags,
+                        unsigned long addr, unsigned long addr_only)
+{
+       if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
+               return -EACCES;
+       return 0;
+}
+
+static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+                            unsigned long prot)
+{
+       return 0;
+}
+
+static int cap_file_lock(struct file *file, unsigned int cmd)
+{
+       return 0;
+}
+
+static int cap_file_fcntl(struct file *file, unsigned int cmd,
+                         unsigned long arg)
+{
+       return 0;
+}
+
+static int cap_file_set_fowner(struct file *file)
+{
+       return 0;
+}
+
+static int cap_file_send_sigiotask(struct task_struct *tsk,
+                                  struct fown_struct *fown, int sig)
+{
+       return 0;
+}
+
+static int cap_file_receive(struct file *file)
+{
+       return 0;
+}
+
+static int cap_dentry_open(struct file *file)
+{
+       return 0;
+}
+
+static int cap_task_create(unsigned long clone_flags)
+{
+       return 0;
+}
+
+static int cap_task_alloc_security(struct task_struct *p)
+{
+       return 0;
+}
+
+static void cap_task_free_security(struct task_struct *p)
+{
+}
+
+static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+       return 0;
+}
+
+static int cap_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
+{
+       return 0;
+}
 
-static int capability_disable;
-module_param_named(disable, capability_disable, int, 0);
+static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
+{
+       return 0;
+}
 
-static int __init capability_init (void)
+static int cap_task_getpgid(struct task_struct *p)
 {
-       if (capability_disable) {
-               printk(KERN_INFO "Capabilities disabled at initialization\n");
-               return 0;
-       }
-       /* register ourselves with the security framework */
-       if (register_security (&capability_ops)) {
-               /* try registering with primary module */
-               if (mod_reg_security (KBUILD_MODNAME, &capability_ops)) {
-                       printk (KERN_INFO "Failure registering capabilities "
-                               "with primary security module.\n");
-                       return -EINVAL;
-               }
-               secondary = 1;
-       }
-       printk (KERN_INFO "Capability LSM initialized%s\n",
-               secondary ? " as secondary" : "");
        return 0;
 }
 
-security_initcall (capability_init);
+static int cap_task_getsid(struct task_struct *p)
+{
+       return 0;
+}
+
+static void cap_task_getsecid(struct task_struct *p, u32 *secid)
+{
+       *secid = 0;
+}
+
+static int cap_task_setgroups(struct group_info *group_info)
+{
+       return 0;
+}
+
+static int cap_task_getioprio(struct task_struct *p)
+{
+       return 0;
+}
+
+static int cap_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+{
+       return 0;
+}
+
+static int cap_task_getscheduler(struct task_struct *p)
+{
+       return 0;
+}
+
+static int cap_task_movememory(struct task_struct *p)
+{
+       return 0;
+}
+
+static int cap_task_wait(struct task_struct *p)
+{
+       return 0;
+}
+
+static int cap_task_kill(struct task_struct *p, struct siginfo *info,
+                        int sig, u32 secid)
+{
+       return 0;
+}
+
+static void cap_task_to_inode(struct task_struct *p, struct inode *inode)
+{
+}
+
+static int cap_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
+{
+       return 0;
+}
+
+static void cap_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+{
+       *secid = 0;
+}
+
+static int cap_msg_msg_alloc_security(struct msg_msg *msg)
+{
+       return 0;
+}
+
+static void cap_msg_msg_free_security(struct msg_msg *msg)
+{
+}
+
+static int cap_msg_queue_alloc_security(struct msg_queue *msq)
+{
+       return 0;
+}
+
+static void cap_msg_queue_free_security(struct msg_queue *msq)
+{
+}
+
+static int cap_msg_queue_associate(struct msg_queue *msq, int msqflg)
+{
+       return 0;
+}
+
+static int cap_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+{
+       return 0;
+}
+
+static int cap_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
+                               int msgflg)
+{
+       return 0;
+}
+
+static int cap_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+                               struct task_struct *target, long type, int mode)
+{
+       return 0;
+}
+
+static int cap_shm_alloc_security(struct shmid_kernel *shp)
+{
+       return 0;
+}
+
+static void cap_shm_free_security(struct shmid_kernel *shp)
+{
+}
+
+static int cap_shm_associate(struct shmid_kernel *shp, int shmflg)
+{
+       return 0;
+}
+
+static int cap_shm_shmctl(struct shmid_kernel *shp, int cmd)
+{
+       return 0;
+}
+
+static int cap_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
+                        int shmflg)
+{
+       return 0;
+}
+
+static int cap_sem_alloc_security(struct sem_array *sma)
+{
+       return 0;
+}
+
+static void cap_sem_free_security(struct sem_array *sma)
+{
+}
+
+static int cap_sem_associate(struct sem_array *sma, int semflg)
+{
+       return 0;
+}
+
+static int cap_sem_semctl(struct sem_array *sma, int cmd)
+{
+       return 0;
+}
+
+static int cap_sem_semop(struct sem_array *sma, struct sembuf *sops,
+                        unsigned nsops, int alter)
+{
+       return 0;
+}
+
+#ifdef CONFIG_SECURITY_NETWORK
+static int cap_unix_stream_connect(struct socket *sock, struct socket *other,
+                                  struct sock *newsk)
+{
+       return 0;
+}
+
+static int cap_unix_may_send(struct socket *sock, struct socket *other)
+{
+       return 0;
+}
+
+static int cap_socket_create(int family, int type, int protocol, int kern)
+{
+       return 0;
+}
+
+static int cap_socket_post_create(struct socket *sock, int family, int type,
+                                 int protocol, int kern)
+{
+       return 0;
+}
+
+static int cap_socket_bind(struct socket *sock, struct sockaddr *address,
+                          int addrlen)
+{
+       return 0;
+}
+
+static int cap_socket_connect(struct socket *sock, struct sockaddr *address,
+                             int addrlen)
+{
+       return 0;
+}
+
+static int cap_socket_listen(struct socket *sock, int backlog)
+{
+       return 0;
+}
+
+static int cap_socket_accept(struct socket *sock, struct socket *newsock)
+{
+       return 0;
+}
+
+static void cap_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+}
+
+static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
+{
+       return 0;
+}
+
+static int cap_socket_recvmsg(struct socket *sock, struct msghdr *msg,
+                             int size, int flags)
+{
+       return 0;
+}
+
+static int cap_socket_getsockname(struct socket *sock)
+{
+       return 0;
+}
+
+static int cap_socket_getpeername(struct socket *sock)
+{
+       return 0;
+}
+
+static int cap_socket_setsockopt(struct socket *sock, int level, int optname)
+{
+       return 0;
+}
+
+static int cap_socket_getsockopt(struct socket *sock, int level, int optname)
+{
+       return 0;
+}
+
+static int cap_socket_shutdown(struct socket *sock, int how)
+{
+       return 0;
+}
+
+static int cap_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       return 0;
+}
+
+static int cap_socket_getpeersec_stream(struct socket *sock,
+                                       char __user *optval,
+                                       int __user *optlen, unsigned len)
+{
+       return -ENOPROTOOPT;
+}
+
+static int cap_socket_getpeersec_dgram(struct socket *sock,
+                                      struct sk_buff *skb, u32 *secid)
+{
+       return -ENOPROTOOPT;
+}
+
+static int cap_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
+{
+       return 0;
+}
+
+static void cap_sk_free_security(struct sock *sk)
+{
+}
+
+static void cap_sk_clone_security(const struct sock *sk, struct sock *newsk)
+{
+}
+
+static void cap_sk_getsecid(struct sock *sk, u32 *secid)
+{
+}
+
+static void cap_sock_graft(struct sock *sk, struct socket *parent)
+{
+}
+
+static int cap_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+                                struct request_sock *req)
+{
+       return 0;
+}
+
+static void cap_inet_csk_clone(struct sock *newsk,
+                              const struct request_sock *req)
+{
+}
+
+static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb)
+{
+}
+
+static void cap_req_classify_flow(const struct request_sock *req,
+                                 struct flowi *fl)
+{
+}
+#endif /* CONFIG_SECURITY_NETWORK */
+
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
+                                         struct xfrm_user_sec_ctx *sec_ctx)
+{
+       return 0;
+}
+
+static int cap_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx,
+                                         struct xfrm_sec_ctx **new_ctxp)
+{
+       return 0;
+}
+
+static void cap_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx)
+{
+}
+
+static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
+{
+       return 0;
+}
+
+static int cap_xfrm_state_alloc_security(struct xfrm_state *x,
+                                        struct xfrm_user_sec_ctx *sec_ctx,
+                                        u32 secid)
+{
+       return 0;
+}
+
+static void cap_xfrm_state_free_security(struct xfrm_state *x)
+{
+}
+
+static int cap_xfrm_state_delete_security(struct xfrm_state *x)
+{
+       return 0;
+}
+
+static int cap_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 sk_sid, u8 dir)
+{
+       return 0;
+}
+
+static int cap_xfrm_state_pol_flow_match(struct xfrm_state *x,
+                                        struct xfrm_policy *xp,
+                                        struct flowi *fl)
+{
+       return 1;
+}
+
+static int cap_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall)
+{
+       return 0;
+}
+
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+static void cap_d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+}
+
+static int cap_getprocattr(struct task_struct *p, char *name, char **value)
+{
+       return -EINVAL;
+}
+
+static int cap_setprocattr(struct task_struct *p, char *name, void *value,
+                          size_t size)
+{
+       return -EINVAL;
+}
+
+static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+{
+       return -EOPNOTSUPP;
+}
+
+static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
+{
+       return -EOPNOTSUPP;
+}
+
+static void cap_release_secctx(char *secdata, u32 seclen)
+{
+}
+
+#ifdef CONFIG_KEYS
+static int cap_key_alloc(struct key *key, struct task_struct *ctx,
+                        unsigned long flags)
+{
+       return 0;
+}
+
+static void cap_key_free(struct key *key)
+{
+}
+
+static int cap_key_permission(key_ref_t key_ref, struct task_struct *context,
+                             key_perm_t perm)
+{
+       return 0;
+}
+
+static int cap_key_getsecurity(struct key *key, char **_buffer)
+{
+       *_buffer = NULL;
+       return 0;
+}
+
+#endif /* CONFIG_KEYS */
+
+#ifdef CONFIG_AUDIT
+static int cap_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
+{
+       return 0;
+}
+
+static int cap_audit_rule_known(struct audit_krule *krule)
+{
+       return 0;
+}
+
+static int cap_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
+                               struct audit_context *actx)
+{
+       return 0;
+}
+
+static void cap_audit_rule_free(void *lsmrule)
+{
+}
+#endif /* CONFIG_AUDIT */
+
+struct security_operations default_security_ops = {
+       .name   = "default",
+};
+
+#define set_to_cap_if_null(ops, function)                              \
+       do {                                                            \
+               if (!ops->function) {                                   \
+                       ops->function = cap_##function;                 \
+                       pr_debug("Had to override the " #function       \
+                                " security operation with the default.\n");\
+                       }                                               \
+       } while (0)
+
+void security_fixup_ops(struct security_operations *ops)
+{
+       set_to_cap_if_null(ops, ptrace);
+       set_to_cap_if_null(ops, capget);
+       set_to_cap_if_null(ops, capset_check);
+       set_to_cap_if_null(ops, capset_set);
+       set_to_cap_if_null(ops, acct);
+       set_to_cap_if_null(ops, capable);
+       set_to_cap_if_null(ops, quotactl);
+       set_to_cap_if_null(ops, quota_on);
+       set_to_cap_if_null(ops, sysctl);
+       set_to_cap_if_null(ops, syslog);
+       set_to_cap_if_null(ops, settime);
+       set_to_cap_if_null(ops, vm_enough_memory);
+       set_to_cap_if_null(ops, bprm_alloc_security);
+       set_to_cap_if_null(ops, bprm_free_security);
+       set_to_cap_if_null(ops, bprm_apply_creds);
+       set_to_cap_if_null(ops, bprm_post_apply_creds);
+       set_to_cap_if_null(ops, bprm_set_security);
+       set_to_cap_if_null(ops, bprm_check_security);
+       set_to_cap_if_null(ops, bprm_secureexec);
+       set_to_cap_if_null(ops, sb_alloc_security);
+       set_to_cap_if_null(ops, sb_free_security);
+       set_to_cap_if_null(ops, sb_copy_data);
+       set_to_cap_if_null(ops, sb_kern_mount);
+       set_to_cap_if_null(ops, sb_show_options);
+       set_to_cap_if_null(ops, sb_statfs);
+       set_to_cap_if_null(ops, sb_mount);
+       set_to_cap_if_null(ops, sb_check_sb);
+       set_to_cap_if_null(ops, sb_umount);
+       set_to_cap_if_null(ops, sb_umount_close);
+       set_to_cap_if_null(ops, sb_umount_busy);
+       set_to_cap_if_null(ops, sb_post_remount);
+       set_to_cap_if_null(ops, sb_post_addmount);
+       set_to_cap_if_null(ops, sb_pivotroot);
+       set_to_cap_if_null(ops, sb_post_pivotroot);
+       set_to_cap_if_null(ops, sb_set_mnt_opts);
+       set_to_cap_if_null(ops, sb_clone_mnt_opts);
+       set_to_cap_if_null(ops, sb_parse_opts_str);
+       set_to_cap_if_null(ops, inode_alloc_security);
+       set_to_cap_if_null(ops, inode_free_security);
+       set_to_cap_if_null(ops, inode_init_security);
+       set_to_cap_if_null(ops, inode_create);
+       set_to_cap_if_null(ops, inode_link);
+       set_to_cap_if_null(ops, inode_unlink);
+       set_to_cap_if_null(ops, inode_symlink);
+       set_to_cap_if_null(ops, inode_mkdir);
+       set_to_cap_if_null(ops, inode_rmdir);
+       set_to_cap_if_null(ops, inode_mknod);
+       set_to_cap_if_null(ops, inode_rename);
+       set_to_cap_if_null(ops, inode_readlink);
+       set_to_cap_if_null(ops, inode_follow_link);
+       set_to_cap_if_null(ops, inode_permission);
+       set_to_cap_if_null(ops, inode_setattr);
+       set_to_cap_if_null(ops, inode_getattr);
+       set_to_cap_if_null(ops, inode_delete);
+       set_to_cap_if_null(ops, inode_setxattr);
+       set_to_cap_if_null(ops, inode_post_setxattr);
+       set_to_cap_if_null(ops, inode_getxattr);
+       set_to_cap_if_null(ops, inode_listxattr);
+       set_to_cap_if_null(ops, inode_removexattr);
+       set_to_cap_if_null(ops, inode_need_killpriv);
+       set_to_cap_if_null(ops, inode_killpriv);
+       set_to_cap_if_null(ops, inode_getsecurity);
+       set_to_cap_if_null(ops, inode_setsecurity);
+       set_to_cap_if_null(ops, inode_listsecurity);
+       set_to_cap_if_null(ops, inode_getsecid);
+       set_to_cap_if_null(ops, file_permission);
+       set_to_cap_if_null(ops, file_alloc_security);
+       set_to_cap_if_null(ops, file_free_security);
+       set_to_cap_if_null(ops, file_ioctl);
+       set_to_cap_if_null(ops, file_mmap);
+       set_to_cap_if_null(ops, file_mprotect);
+       set_to_cap_if_null(ops, file_lock);
+       set_to_cap_if_null(ops, file_fcntl);
+       set_to_cap_if_null(ops, file_set_fowner);
+       set_to_cap_if_null(ops, file_send_sigiotask);
+       set_to_cap_if_null(ops, file_receive);
+       set_to_cap_if_null(ops, dentry_open);
+       set_to_cap_if_null(ops, task_create);
+       set_to_cap_if_null(ops, task_alloc_security);
+       set_to_cap_if_null(ops, task_free_security);
+       set_to_cap_if_null(ops, task_setuid);
+       set_to_cap_if_null(ops, task_post_setuid);
+       set_to_cap_if_null(ops, task_setgid);
+       set_to_cap_if_null(ops, task_setpgid);
+       set_to_cap_if_null(ops, task_getpgid);
+       set_to_cap_if_null(ops, task_getsid);
+       set_to_cap_if_null(ops, task_getsecid);
+       set_to_cap_if_null(ops, task_setgroups);
+       set_to_cap_if_null(ops, task_setnice);
+       set_to_cap_if_null(ops, task_setioprio);
+       set_to_cap_if_null(ops, task_getioprio);
+       set_to_cap_if_null(ops, task_setrlimit);
+       set_to_cap_if_null(ops, task_setscheduler);
+       set_to_cap_if_null(ops, task_getscheduler);
+       set_to_cap_if_null(ops, task_movememory);
+       set_to_cap_if_null(ops, task_wait);
+       set_to_cap_if_null(ops, task_kill);
+       set_to_cap_if_null(ops, task_prctl);
+       set_to_cap_if_null(ops, task_reparent_to_init);
+       set_to_cap_if_null(ops, task_to_inode);
+       set_to_cap_if_null(ops, ipc_permission);
+       set_to_cap_if_null(ops, ipc_getsecid);
+       set_to_cap_if_null(ops, msg_msg_alloc_security);
+       set_to_cap_if_null(ops, msg_msg_free_security);
+       set_to_cap_if_null(ops, msg_queue_alloc_security);
+       set_to_cap_if_null(ops, msg_queue_free_security);
+       set_to_cap_if_null(ops, msg_queue_associate);
+       set_to_cap_if_null(ops, msg_queue_msgctl);
+       set_to_cap_if_null(ops, msg_queue_msgsnd);
+       set_to_cap_if_null(ops, msg_queue_msgrcv);
+       set_to_cap_if_null(ops, shm_alloc_security);
+       set_to_cap_if_null(ops, shm_free_security);
+       set_to_cap_if_null(ops, shm_associate);
+       set_to_cap_if_null(ops, shm_shmctl);
+       set_to_cap_if_null(ops, shm_shmat);
+       set_to_cap_if_null(ops, sem_alloc_security);
+       set_to_cap_if_null(ops, sem_free_security);
+       set_to_cap_if_null(ops, sem_associate);
+       set_to_cap_if_null(ops, sem_semctl);
+       set_to_cap_if_null(ops, sem_semop);
+       set_to_cap_if_null(ops, netlink_send);
+       set_to_cap_if_null(ops, netlink_recv);
+       set_to_cap_if_null(ops, d_instantiate);
+       set_to_cap_if_null(ops, getprocattr);
+       set_to_cap_if_null(ops, setprocattr);
+       set_to_cap_if_null(ops, secid_to_secctx);
+       set_to_cap_if_null(ops, secctx_to_secid);
+       set_to_cap_if_null(ops, release_secctx);
+#ifdef CONFIG_SECURITY_NETWORK
+       set_to_cap_if_null(ops, unix_stream_connect);
+       set_to_cap_if_null(ops, unix_may_send);
+       set_to_cap_if_null(ops, socket_create);
+       set_to_cap_if_null(ops, socket_post_create);
+       set_to_cap_if_null(ops, socket_bind);
+       set_to_cap_if_null(ops, socket_connect);
+       set_to_cap_if_null(ops, socket_listen);
+       set_to_cap_if_null(ops, socket_accept);
+       set_to_cap_if_null(ops, socket_post_accept);
+       set_to_cap_if_null(ops, socket_sendmsg);
+       set_to_cap_if_null(ops, socket_recvmsg);
+       set_to_cap_if_null(ops, socket_getsockname);
+       set_to_cap_if_null(ops, socket_getpeername);
+       set_to_cap_if_null(ops, socket_setsockopt);
+       set_to_cap_if_null(ops, socket_getsockopt);
+       set_to_cap_if_null(ops, socket_shutdown);
+       set_to_cap_if_null(ops, socket_sock_rcv_skb);
+       set_to_cap_if_null(ops, socket_getpeersec_stream);
+       set_to_cap_if_null(ops, socket_getpeersec_dgram);
+       set_to_cap_if_null(ops, sk_alloc_security);
+       set_to_cap_if_null(ops, sk_free_security);
+       set_to_cap_if_null(ops, sk_clone_security);
+       set_to_cap_if_null(ops, sk_getsecid);
+       set_to_cap_if_null(ops, sock_graft);
+       set_to_cap_if_null(ops, inet_conn_request);
+       set_to_cap_if_null(ops, inet_csk_clone);
+       set_to_cap_if_null(ops, inet_conn_established);
+       set_to_cap_if_null(ops, req_classify_flow);
+#endif /* CONFIG_SECURITY_NETWORK */
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+       set_to_cap_if_null(ops, xfrm_policy_alloc_security);
+       set_to_cap_if_null(ops, xfrm_policy_clone_security);
+       set_to_cap_if_null(ops, xfrm_policy_free_security);
+       set_to_cap_if_null(ops, xfrm_policy_delete_security);
+       set_to_cap_if_null(ops, xfrm_state_alloc_security);
+       set_to_cap_if_null(ops, xfrm_state_free_security);
+       set_to_cap_if_null(ops, xfrm_state_delete_security);
+       set_to_cap_if_null(ops, xfrm_policy_lookup);
+       set_to_cap_if_null(ops, xfrm_state_pol_flow_match);
+       set_to_cap_if_null(ops, xfrm_decode_session);
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+#ifdef CONFIG_KEYS
+       set_to_cap_if_null(ops, key_alloc);
+       set_to_cap_if_null(ops, key_free);
+       set_to_cap_if_null(ops, key_permission);
+       set_to_cap_if_null(ops, key_getsecurity);
+#endif /* CONFIG_KEYS */
+#ifdef CONFIG_AUDIT
+       set_to_cap_if_null(ops, audit_rule_init);
+       set_to_cap_if_null(ops, audit_rule_known);
+       set_to_cap_if_null(ops, audit_rule_match);
+       set_to_cap_if_null(ops, audit_rule_free);
+#endif
+}
index 33d34330841344f7329e1b1f313cc531c65aa7a9..0b6537a3672d8822baf4b10627f142e9afc1102b 100644 (file)
@@ -63,7 +63,8 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
        return 0;
 }
 
-int cap_ptrace (struct task_struct *parent, struct task_struct *child)
+int cap_ptrace (struct task_struct *parent, struct task_struct *child,
+               unsigned int mode)
 {
        /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
        if (!cap_issubset(child->cap_permitted, parent->cap_permitted) &&
diff --git a/security/dummy.c b/security/dummy.c
deleted file mode 100644 (file)
index b891688..0000000
+++ /dev/null
@@ -1,1251 +0,0 @@
-/*
- * Stub functions for the default security function pointers in case no
- * security model is loaded.
- *
- * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com>
- * Copyright (C) 2001-2002  Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com>
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- */
-
-#undef DEBUG
-
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/mman.h>
-#include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <linux/security.h>
-#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <net/sock.h>
-#include <linux/xattr.h>
-#include <linux/hugetlb.h>
-#include <linux/ptrace.h>
-#include <linux/file.h>
-#include <linux/prctl.h>
-#include <linux/securebits.h>
-
-static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
-{
-       return 0;
-}
-
-static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
-                        kernel_cap_t * inheritable, kernel_cap_t * permitted)
-{
-       if (target->euid == 0) {
-               cap_set_full(*permitted);
-               cap_set_init_eff(*effective);
-       } else {
-               cap_clear(*permitted);
-               cap_clear(*effective);
-       }
-
-       cap_clear(*inheritable);
-
-       if (target->fsuid != 0) {
-               *permitted = cap_drop_fs_set(*permitted);
-               *effective = cap_drop_fs_set(*effective);
-       }
-       return 0;
-}
-
-static int dummy_capset_check (struct task_struct *target,
-                              kernel_cap_t * effective,
-                              kernel_cap_t * inheritable,
-                              kernel_cap_t * permitted)
-{
-       return -EPERM;
-}
-
-static void dummy_capset_set (struct task_struct *target,
-                             kernel_cap_t * effective,
-                             kernel_cap_t * inheritable,
-                             kernel_cap_t * permitted)
-{
-       return;
-}
-
-static int dummy_acct (struct file *file)
-{
-       return 0;
-}
-
-static int dummy_capable (struct task_struct *tsk, int cap)
-{
-       if (cap_raised (tsk->cap_effective, cap))
-               return 0;
-       return -EPERM;
-}
-
-static int dummy_sysctl (ctl_table * table, int op)
-{
-       return 0;
-}
-
-static int dummy_quotactl (int cmds, int type, int id, struct super_block *sb)
-{
-       return 0;
-}
-
-static int dummy_quota_on (struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_syslog (int type)
-{
-       if ((type != 3 && type != 10) && current->euid)
-               return -EPERM;
-       return 0;
-}
-
-static int dummy_settime(struct timespec *ts, struct timezone *tz)
-{
-       if (!capable(CAP_SYS_TIME))
-               return -EPERM;
-       return 0;
-}
-
-static int dummy_vm_enough_memory(struct mm_struct *mm, long pages)
-{
-       int cap_sys_admin = 0;
-
-       if (dummy_capable(current, CAP_SYS_ADMIN) == 0)
-               cap_sys_admin = 1;
-       return __vm_enough_memory(mm, pages, cap_sys_admin);
-}
-
-static int dummy_bprm_alloc_security (struct linux_binprm *bprm)
-{
-       return 0;
-}
-
-static void dummy_bprm_free_security (struct linux_binprm *bprm)
-{
-       return;
-}
-
-static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
-{
-       if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
-               set_dumpable(current->mm, suid_dumpable);
-
-               if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) {
-                       bprm->e_uid = current->uid;
-                       bprm->e_gid = current->gid;
-               }
-       }
-
-       current->suid = current->euid = current->fsuid = bprm->e_uid;
-       current->sgid = current->egid = current->fsgid = bprm->e_gid;
-
-       dummy_capget(current, &current->cap_effective, &current->cap_inheritable, &current->cap_permitted);
-}
-
-static void dummy_bprm_post_apply_creds (struct linux_binprm *bprm)
-{
-       return;
-}
-
-static int dummy_bprm_set_security (struct linux_binprm *bprm)
-{
-       return 0;
-}
-
-static int dummy_bprm_check_security (struct linux_binprm *bprm)
-{
-       return 0;
-}
-
-static int dummy_bprm_secureexec (struct linux_binprm *bprm)
-{
-       /* The new userland will simply use the value provided
-          in the AT_SECURE field to decide whether secure mode
-          is required.  Hence, this logic is required to preserve
-          the legacy decision algorithm used by the old userland. */
-       return (current->euid != current->uid ||
-               current->egid != current->gid);
-}
-
-static int dummy_sb_alloc_security (struct super_block *sb)
-{
-       return 0;
-}
-
-static void dummy_sb_free_security (struct super_block *sb)
-{
-       return;
-}
-
-static int dummy_sb_copy_data (char *orig, char *copy)
-{
-       return 0;
-}
-
-static int dummy_sb_kern_mount (struct super_block *sb, void *data)
-{
-       return 0;
-}
-
-static int dummy_sb_statfs (struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_sb_mount (char *dev_name, struct path *path, char *type,
-                          unsigned long flags, void *data)
-{
-       return 0;
-}
-
-static int dummy_sb_check_sb (struct vfsmount *mnt, struct path *path)
-{
-       return 0;
-}
-
-static int dummy_sb_umount (struct vfsmount *mnt, int flags)
-{
-       return 0;
-}
-
-static void dummy_sb_umount_close (struct vfsmount *mnt)
-{
-       return;
-}
-
-static void dummy_sb_umount_busy (struct vfsmount *mnt)
-{
-       return;
-}
-
-static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,
-                                  void *data)
-{
-       return;
-}
-
-
-static void dummy_sb_post_addmount (struct vfsmount *mnt, struct path *path)
-{
-       return;
-}
-
-static int dummy_sb_pivotroot (struct path *old_path, struct path *new_path)
-{
-       return 0;
-}
-
-static void dummy_sb_post_pivotroot (struct path *old_path, struct path *new_path)
-{
-       return;
-}
-
-static int dummy_sb_get_mnt_opts(const struct super_block *sb,
-                                struct security_mnt_opts *opts)
-{
-       security_init_mnt_opts(opts);
-       return 0;
-}
-
-static int dummy_sb_set_mnt_opts(struct super_block *sb,
-                                struct security_mnt_opts *opts)
-{
-       if (unlikely(opts->num_mnt_opts))
-               return -EOPNOTSUPP;
-       return 0;
-}
-
-static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb,
-                                   struct super_block *newsb)
-{
-       return;
-}
-
-static int dummy_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
-{
-       return 0;
-}
-
-static int dummy_inode_alloc_security (struct inode *inode)
-{
-       return 0;
-}
-
-static void dummy_inode_free_security (struct inode *inode)
-{
-       return;
-}
-
-static int dummy_inode_init_security (struct inode *inode, struct inode *dir,
-                                     char **name, void **value, size_t *len)
-{
-       return -EOPNOTSUPP;
-}
-
-static int dummy_inode_create (struct inode *inode, struct dentry *dentry,
-                              int mask)
-{
-       return 0;
-}
-
-static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode,
-                            struct dentry *new_dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry,
-                               const char *name)
-{
-       return 0;
-}
-
-static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry,
-                             int mask)
-{
-       return 0;
-}
-
-static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry,
-                             int mode, dev_t dev)
-{
-       return 0;
-}
-
-static int dummy_inode_rename (struct inode *old_inode,
-                              struct dentry *old_dentry,
-                              struct inode *new_inode,
-                              struct dentry *new_dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_readlink (struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_follow_link (struct dentry *dentry,
-                                   struct nameidata *nameidata)
-{
-       return 0;
-}
-
-static int dummy_inode_permission (struct inode *inode, int mask, struct nameidata *nd)
-{
-       return 0;
-}
-
-static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr)
-{
-       return 0;
-}
-
-static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
-{
-       return 0;
-}
-
-static void dummy_inode_delete (struct inode *ino)
-{
-       return;
-}
-
-static int dummy_inode_setxattr (struct dentry *dentry, const char *name,
-                                const void *value, size_t size, int flags)
-{
-       if (!strncmp(name, XATTR_SECURITY_PREFIX,
-                    sizeof(XATTR_SECURITY_PREFIX) - 1) &&
-           !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       return 0;
-}
-
-static void dummy_inode_post_setxattr (struct dentry *dentry, const char *name,
-                                      const void *value, size_t size,
-                                      int flags)
-{
-}
-
-static int dummy_inode_getxattr (struct dentry *dentry, const char *name)
-{
-       return 0;
-}
-
-static int dummy_inode_listxattr (struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_removexattr (struct dentry *dentry, const char *name)
-{
-       if (!strncmp(name, XATTR_SECURITY_PREFIX,
-                    sizeof(XATTR_SECURITY_PREFIX) - 1) &&
-           !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       return 0;
-}
-
-static int dummy_inode_need_killpriv(struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_killpriv(struct dentry *dentry)
-{
-       return 0;
-}
-
-static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
-{
-       return -EOPNOTSUPP;
-}
-
-static int dummy_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
-{
-       return -EOPNOTSUPP;
-}
-
-static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
-{
-       return 0;
-}
-
-static void dummy_inode_getsecid(const struct inode *inode, u32 *secid)
-{
-       *secid = 0;
-}
-
-static int dummy_file_permission (struct file *file, int mask)
-{
-       return 0;
-}
-
-static int dummy_file_alloc_security (struct file *file)
-{
-       return 0;
-}
-
-static void dummy_file_free_security (struct file *file)
-{
-       return;
-}
-
-static int dummy_file_ioctl (struct file *file, unsigned int command,
-                            unsigned long arg)
-{
-       return 0;
-}
-
-static int dummy_file_mmap (struct file *file, unsigned long reqprot,
-                           unsigned long prot,
-                           unsigned long flags,
-                           unsigned long addr,
-                           unsigned long addr_only)
-{
-       if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
-               return -EACCES;
-       return 0;
-}
-
-static int dummy_file_mprotect (struct vm_area_struct *vma,
-                               unsigned long reqprot,
-                               unsigned long prot)
-{
-       return 0;
-}
-
-static int dummy_file_lock (struct file *file, unsigned int cmd)
-{
-       return 0;
-}
-
-static int dummy_file_fcntl (struct file *file, unsigned int cmd,
-                            unsigned long arg)
-{
-       return 0;
-}
-
-static int dummy_file_set_fowner (struct file *file)
-{
-       return 0;
-}
-
-static int dummy_file_send_sigiotask (struct task_struct *tsk,
-                                     struct fown_struct *fown, int sig)
-{
-       return 0;
-}
-
-static int dummy_file_receive (struct file *file)
-{
-       return 0;
-}
-
-static int dummy_dentry_open (struct file *file)
-{
-       return 0;
-}
-
-static int dummy_task_create (unsigned long clone_flags)
-{
-       return 0;
-}
-
-static int dummy_task_alloc_security (struct task_struct *p)
-{
-       return 0;
-}
-
-static void dummy_task_free_security (struct task_struct *p)
-{
-       return;
-}
-
-static int dummy_task_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
-{
-       return 0;
-}
-
-static int dummy_task_post_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
-{
-       dummy_capget(current, &current->cap_effective, &current->cap_inheritable, &current->cap_permitted);
-       return 0;
-}
-
-static int dummy_task_setgid (gid_t id0, gid_t id1, gid_t id2, int flags)
-{
-       return 0;
-}
-
-static int dummy_task_setpgid (struct task_struct *p, pid_t pgid)
-{
-       return 0;
-}
-
-static int dummy_task_getpgid (struct task_struct *p)
-{
-       return 0;
-}
-
-static int dummy_task_getsid (struct task_struct *p)
-{
-       return 0;
-}
-
-static void dummy_task_getsecid (struct task_struct *p, u32 *secid)
-{
-       *secid = 0;
-}
-
-static int dummy_task_setgroups (struct group_info *group_info)
-{
-       return 0;
-}
-
-static int dummy_task_setnice (struct task_struct *p, int nice)
-{
-       return 0;
-}
-
-static int dummy_task_setioprio (struct task_struct *p, int ioprio)
-{
-       return 0;
-}
-
-static int dummy_task_getioprio (struct task_struct *p)
-{
-       return 0;
-}
-
-static int dummy_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
-{
-       return 0;
-}
-
-static int dummy_task_setscheduler (struct task_struct *p, int policy,
-                                   struct sched_param *lp)
-{
-       return 0;
-}
-
-static int dummy_task_getscheduler (struct task_struct *p)
-{
-       return 0;
-}
-
-static int dummy_task_movememory (struct task_struct *p)
-{
-       return 0;
-}
-
-static int dummy_task_wait (struct task_struct *p)
-{
-       return 0;
-}
-
-static int dummy_task_kill (struct task_struct *p, struct siginfo *info,
-                           int sig, u32 secid)
-{
-       return 0;
-}
-
-static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3,
-                            unsigned long arg4, unsigned long arg5, long *rc_p)
-{
-       switch (option) {
-       case PR_CAPBSET_READ:
-               *rc_p = (cap_valid(arg2) ? 1 : -EINVAL);
-               break;
-       case PR_GET_KEEPCAPS:
-               *rc_p = issecure(SECURE_KEEP_CAPS);
-               break;
-       case PR_SET_KEEPCAPS:
-               if (arg2 > 1)
-                       *rc_p = -EINVAL;
-               else if (arg2)
-                       current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
-               else
-                       current->securebits &=
-                               ~issecure_mask(SECURE_KEEP_CAPS);
-               break;
-       default:
-               return 0;
-       }
-
-       return 1;
-}
-
-static void dummy_task_reparent_to_init (struct task_struct *p)
-{
-       p->euid = p->fsuid = 0;
-       return;
-}
-
-static void dummy_task_to_inode(struct task_struct *p, struct inode *inode)
-{ }
-
-static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
-{
-       return 0;
-}
-
-static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
-{
-       *secid = 0;
-}
-
-static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
-{
-       return 0;
-}
-
-static void dummy_msg_msg_free_security (struct msg_msg *msg)
-{
-       return;
-}
-
-static int dummy_msg_queue_alloc_security (struct msg_queue *msq)
-{
-       return 0;
-}
-
-static void dummy_msg_queue_free_security (struct msg_queue *msq)
-{
-       return;
-}
-
-static int dummy_msg_queue_associate (struct msg_queue *msq, 
-                                     int msqflg)
-{
-       return 0;
-}
-
-static int dummy_msg_queue_msgctl (struct msg_queue *msq, int cmd)
-{
-       return 0;
-}
-
-static int dummy_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
-                                  int msgflg)
-{
-       return 0;
-}
-
-static int dummy_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg,
-                                  struct task_struct *target, long type,
-                                  int mode)
-{
-       return 0;
-}
-
-static int dummy_shm_alloc_security (struct shmid_kernel *shp)
-{
-       return 0;
-}
-
-static void dummy_shm_free_security (struct shmid_kernel *shp)
-{
-       return;
-}
-
-static int dummy_shm_associate (struct shmid_kernel *shp, int shmflg)
-{
-       return 0;
-}
-
-static int dummy_shm_shmctl (struct shmid_kernel *shp, int cmd)
-{
-       return 0;
-}
-
-static int dummy_shm_shmat (struct shmid_kernel *shp, char __user *shmaddr,
-                           int shmflg)
-{
-       return 0;
-}
-
-static int dummy_sem_alloc_security (struct sem_array *sma)
-{
-       return 0;
-}
-
-static void dummy_sem_free_security (struct sem_array *sma)
-{
-       return;
-}
-
-static int dummy_sem_associate (struct sem_array *sma, int semflg)
-{
-       return 0;
-}
-
-static int dummy_sem_semctl (struct sem_array *sma, int cmd)
-{
-       return 0;
-}
-
-static int dummy_sem_semop (struct sem_array *sma, 
-                           struct sembuf *sops, unsigned nsops, int alter)
-{
-       return 0;
-}
-
-static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb)
-{
-       NETLINK_CB(skb).eff_cap = current->cap_effective;
-       return 0;
-}
-
-static int dummy_netlink_recv (struct sk_buff *skb, int cap)
-{
-       if (!cap_raised (NETLINK_CB (skb).eff_cap, cap))
-               return -EPERM;
-       return 0;
-}
-
-#ifdef CONFIG_SECURITY_NETWORK
-static int dummy_unix_stream_connect (struct socket *sock,
-                                     struct socket *other,
-                                     struct sock *newsk)
-{
-       return 0;
-}
-
-static int dummy_unix_may_send (struct socket *sock,
-                               struct socket *other)
-{
-       return 0;
-}
-
-static int dummy_socket_create (int family, int type,
-                               int protocol, int kern)
-{
-       return 0;
-}
-
-static int dummy_socket_post_create (struct socket *sock, int family, int type,
-                                    int protocol, int kern)
-{
-       return 0;
-}
-
-static int dummy_socket_bind (struct socket *sock, struct sockaddr *address,
-                             int addrlen)
-{
-       return 0;
-}
-
-static int dummy_socket_connect (struct socket *sock, struct sockaddr *address,
-                                int addrlen)
-{
-       return 0;
-}
-
-static int dummy_socket_listen (struct socket *sock, int backlog)
-{
-       return 0;
-}
-
-static int dummy_socket_accept (struct socket *sock, struct socket *newsock)
-{
-       return 0;
-}
-
-static void dummy_socket_post_accept (struct socket *sock, 
-                                     struct socket *newsock)
-{
-       return;
-}
-
-static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
-                                int size)
-{
-       return 0;
-}
-
-static int dummy_socket_recvmsg (struct socket *sock, struct msghdr *msg,
-                                int size, int flags)
-{
-       return 0;
-}
-
-static int dummy_socket_getsockname (struct socket *sock)
-{
-       return 0;
-}
-
-static int dummy_socket_getpeername (struct socket *sock)
-{
-       return 0;
-}
-
-static int dummy_socket_setsockopt (struct socket *sock, int level, int optname)
-{
-       return 0;
-}
-
-static int dummy_socket_getsockopt (struct socket *sock, int level, int optname)
-{
-       return 0;
-}
-
-static int dummy_socket_shutdown (struct socket *sock, int how)
-{
-       return 0;
-}
-
-static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
-{
-       return 0;
-}
-
-static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optval,
-                                         int __user *optlen, unsigned len)
-{
-       return -ENOPROTOOPT;
-}
-
-static int dummy_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
-{
-       return -ENOPROTOOPT;
-}
-
-static inline int dummy_sk_alloc_security (struct sock *sk, int family, gfp_t priority)
-{
-       return 0;
-}
-
-static inline void dummy_sk_free_security (struct sock *sk)
-{
-}
-
-static inline void dummy_sk_clone_security (const struct sock *sk, struct sock *newsk)
-{
-}
-
-static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid)
-{
-}
-
-static inline void dummy_sock_graft(struct sock* sk, struct socket *parent)
-{
-}
-
-static inline int dummy_inet_conn_request(struct sock *sk,
-                       struct sk_buff *skb, struct request_sock *req)
-{
-       return 0;
-}
-
-static inline void dummy_inet_csk_clone(struct sock *newsk,
-                       const struct request_sock *req)
-{
-}
-
-static inline void dummy_inet_conn_established(struct sock *sk,
-                       struct sk_buff *skb)
-{
-}
-
-static inline void dummy_req_classify_flow(const struct request_sock *req,
-                       struct flowi *fl)
-{
-}
-#endif /* CONFIG_SECURITY_NETWORK */
-
-#ifdef CONFIG_SECURITY_NETWORK_XFRM
-static int dummy_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
-                                           struct xfrm_user_sec_ctx *sec_ctx)
-{
-       return 0;
-}
-
-static inline int dummy_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx,
-                                          struct xfrm_sec_ctx **new_ctxp)
-{
-       return 0;
-}
-
-static void dummy_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx)
-{
-}
-
-static int dummy_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
-{
-       return 0;
-}
-
-static int dummy_xfrm_state_alloc_security(struct xfrm_state *x,
-       struct xfrm_user_sec_ctx *sec_ctx, u32 secid)
-{
-       return 0;
-}
-
-static void dummy_xfrm_state_free_security(struct xfrm_state *x)
-{
-}
-
-static int dummy_xfrm_state_delete_security(struct xfrm_state *x)
-{
-       return 0;
-}
-
-static int dummy_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx,
-                                   u32 sk_sid, u8 dir)
-{
-       return 0;
-}
-
-static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x,
-                               struct xfrm_policy *xp, struct flowi *fl)
-{
-       return 1;
-}
-
-static int dummy_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall)
-{
-       return 0;
-}
-
-#endif /* CONFIG_SECURITY_NETWORK_XFRM */
-static int dummy_register_security (const char *name, struct security_operations *ops)
-{
-       return -EINVAL;
-}
-
-static void dummy_d_instantiate (struct dentry *dentry, struct inode *inode)
-{
-       return;
-}
-
-static int dummy_getprocattr(struct task_struct *p, char *name, char **value)
-{
-       return -EINVAL;
-}
-
-static int dummy_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
-{
-       return -EINVAL;
-}
-
-static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
-{
-       return -EOPNOTSUPP;
-}
-
-static int dummy_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
-{
-       return -EOPNOTSUPP;
-}
-
-static void dummy_release_secctx(char *secdata, u32 seclen)
-{
-}
-
-#ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
-                                 unsigned long flags)
-{
-       return 0;
-}
-
-static inline void dummy_key_free(struct key *key)
-{
-}
-
-static inline int dummy_key_permission(key_ref_t key_ref,
-                                      struct task_struct *context,
-                                      key_perm_t perm)
-{
-       return 0;
-}
-
-static int dummy_key_getsecurity(struct key *key, char **_buffer)
-{
-       *_buffer = NULL;
-       return 0;
-}
-
-#endif /* CONFIG_KEYS */
-
-#ifdef CONFIG_AUDIT
-static inline int dummy_audit_rule_init(u32 field, u32 op, char *rulestr,
-                                       void **lsmrule)
-{
-       return 0;
-}
-
-static inline int dummy_audit_rule_known(struct audit_krule *krule)
-{
-       return 0;
-}
-
-static inline int dummy_audit_rule_match(u32 secid, u32 field, u32 op,
-                                        void *lsmrule,
-                                        struct audit_context *actx)
-{
-       return 0;
-}
-
-static inline void dummy_audit_rule_free(void *lsmrule)
-{ }
-
-#endif /* CONFIG_AUDIT */
-
-struct security_operations dummy_security_ops = {
-       .name = "dummy",
-};
-
-#define set_to_dummy_if_null(ops, function)                            \
-       do {                                                            \
-               if (!ops->function) {                                   \
-                       ops->function = dummy_##function;               \
-                       pr_debug("Had to override the " #function       \
-                                " security operation with the dummy one.\n");\
-                       }                                               \
-       } while (0)
-
-void security_fixup_ops (struct security_operations *ops)
-{
-       set_to_dummy_if_null(ops, ptrace);
-       set_to_dummy_if_null(ops, capget);
-       set_to_dummy_if_null(ops, capset_check);
-       set_to_dummy_if_null(ops, capset_set);
-       set_to_dummy_if_null(ops, acct);
-       set_to_dummy_if_null(ops, capable);
-       set_to_dummy_if_null(ops, quotactl);
-       set_to_dummy_if_null(ops, quota_on);
-       set_to_dummy_if_null(ops, sysctl);
-       set_to_dummy_if_null(ops, syslog);
-       set_to_dummy_if_null(ops, settime);
-       set_to_dummy_if_null(ops, vm_enough_memory);
-       set_to_dummy_if_null(ops, bprm_alloc_security);
-       set_to_dummy_if_null(ops, bprm_free_security);
-       set_to_dummy_if_null(ops, bprm_apply_creds);
-       set_to_dummy_if_null(ops, bprm_post_apply_creds);
-       set_to_dummy_if_null(ops, bprm_set_security);
-       set_to_dummy_if_null(ops, bprm_check_security);
-       set_to_dummy_if_null(ops, bprm_secureexec);
-       set_to_dummy_if_null(ops, sb_alloc_security);
-       set_to_dummy_if_null(ops, sb_free_security);
-       set_to_dummy_if_null(ops, sb_copy_data);
-       set_to_dummy_if_null(ops, sb_kern_mount);
-       set_to_dummy_if_null(ops, sb_statfs);
-       set_to_dummy_if_null(ops, sb_mount);
-       set_to_dummy_if_null(ops, sb_check_sb);
-       set_to_dummy_if_null(ops, sb_umount);
-       set_to_dummy_if_null(ops, sb_umount_close);
-       set_to_dummy_if_null(ops, sb_umount_busy);
-       set_to_dummy_if_null(ops, sb_post_remount);
-       set_to_dummy_if_null(ops, sb_post_addmount);
-       set_to_dummy_if_null(ops, sb_pivotroot);
-       set_to_dummy_if_null(ops, sb_post_pivotroot);
-       set_to_dummy_if_null(ops, sb_get_mnt_opts);
-       set_to_dummy_if_null(ops, sb_set_mnt_opts);
-       set_to_dummy_if_null(ops, sb_clone_mnt_opts);
-       set_to_dummy_if_null(ops, sb_parse_opts_str);
-       set_to_dummy_if_null(ops, inode_alloc_security);
-       set_to_dummy_if_null(ops, inode_free_security);
-       set_to_dummy_if_null(ops, inode_init_security);
-       set_to_dummy_if_null(ops, inode_create);
-       set_to_dummy_if_null(ops, inode_link);
-       set_to_dummy_if_null(ops, inode_unlink);
-       set_to_dummy_if_null(ops, inode_symlink);
-       set_to_dummy_if_null(ops, inode_mkdir);
-       set_to_dummy_if_null(ops, inode_rmdir);
-       set_to_dummy_if_null(ops, inode_mknod);
-       set_to_dummy_if_null(ops, inode_rename);
-       set_to_dummy_if_null(ops, inode_readlink);
-       set_to_dummy_if_null(ops, inode_follow_link);
-       set_to_dummy_if_null(ops, inode_permission);
-       set_to_dummy_if_null(ops, inode_setattr);
-       set_to_dummy_if_null(ops, inode_getattr);
-       set_to_dummy_if_null(ops, inode_delete);
-       set_to_dummy_if_null(ops, inode_setxattr);
-       set_to_dummy_if_null(ops, inode_post_setxattr);
-       set_to_dummy_if_null(ops, inode_getxattr);
-       set_to_dummy_if_null(ops, inode_listxattr);
-       set_to_dummy_if_null(ops, inode_removexattr);
-       set_to_dummy_if_null(ops, inode_need_killpriv);
-       set_to_dummy_if_null(ops, inode_killpriv);
-       set_to_dummy_if_null(ops, inode_getsecurity);
-       set_to_dummy_if_null(ops, inode_setsecurity);
-       set_to_dummy_if_null(ops, inode_listsecurity);
-       set_to_dummy_if_null(ops, inode_getsecid);
-       set_to_dummy_if_null(ops, file_permission);
-       set_to_dummy_if_null(ops, file_alloc_security);
-       set_to_dummy_if_null(ops, file_free_security);
-       set_to_dummy_if_null(ops, file_ioctl);
-       set_to_dummy_if_null(ops, file_mmap);
-       set_to_dummy_if_null(ops, file_mprotect);
-       set_to_dummy_if_null(ops, file_lock);
-       set_to_dummy_if_null(ops, file_fcntl);
-       set_to_dummy_if_null(ops, file_set_fowner);
-       set_to_dummy_if_null(ops, file_send_sigiotask);
-       set_to_dummy_if_null(ops, file_receive);
-       set_to_dummy_if_null(ops, dentry_open);
-       set_to_dummy_if_null(ops, task_create);
-       set_to_dummy_if_null(ops, task_alloc_security);
-       set_to_dummy_if_null(ops, task_free_security);
-       set_to_dummy_if_null(ops, task_setuid);
-       set_to_dummy_if_null(ops, task_post_setuid);
-       set_to_dummy_if_null(ops, task_setgid);
-       set_to_dummy_if_null(ops, task_setpgid);
-       set_to_dummy_if_null(ops, task_getpgid);
-       set_to_dummy_if_null(ops, task_getsid);
-       set_to_dummy_if_null(ops, task_getsecid);
-       set_to_dummy_if_null(ops, task_setgroups);
-       set_to_dummy_if_null(ops, task_setnice);
-       set_to_dummy_if_null(ops, task_setioprio);
-       set_to_dummy_if_null(ops, task_getioprio);
-       set_to_dummy_if_null(ops, task_setrlimit);
-       set_to_dummy_if_null(ops, task_setscheduler);
-       set_to_dummy_if_null(ops, task_getscheduler);
-       set_to_dummy_if_null(ops, task_movememory);
-       set_to_dummy_if_null(ops, task_wait);
-       set_to_dummy_if_null(ops, task_kill);
-       set_to_dummy_if_null(ops, task_prctl);
-       set_to_dummy_if_null(ops, task_reparent_to_init);
-       set_to_dummy_if_null(ops, task_to_inode);
-       set_to_dummy_if_null(ops, ipc_permission);
-       set_to_dummy_if_null(ops, ipc_getsecid);
-       set_to_dummy_if_null(ops, msg_msg_alloc_security);
-       set_to_dummy_if_null(ops, msg_msg_free_security);
-       set_to_dummy_if_null(ops, msg_queue_alloc_security);
-       set_to_dummy_if_null(ops, msg_queue_free_security);
-       set_to_dummy_if_null(ops, msg_queue_associate);
-       set_to_dummy_if_null(ops, msg_queue_msgctl);
-       set_to_dummy_if_null(ops, msg_queue_msgsnd);
-       set_to_dummy_if_null(ops, msg_queue_msgrcv);
-       set_to_dummy_if_null(ops, shm_alloc_security);
-       set_to_dummy_if_null(ops, shm_free_security);
-       set_to_dummy_if_null(ops, shm_associate);
-       set_to_dummy_if_null(ops, shm_shmctl);
-       set_to_dummy_if_null(ops, shm_shmat);
-       set_to_dummy_if_null(ops, sem_alloc_security);
-       set_to_dummy_if_null(ops, sem_free_security);
-       set_to_dummy_if_null(ops, sem_associate);
-       set_to_dummy_if_null(ops, sem_semctl);
-       set_to_dummy_if_null(ops, sem_semop);
-       set_to_dummy_if_null(ops, netlink_send);
-       set_to_dummy_if_null(ops, netlink_recv);
-       set_to_dummy_if_null(ops, register_security);
-       set_to_dummy_if_null(ops, d_instantiate);
-       set_to_dummy_if_null(ops, getprocattr);
-       set_to_dummy_if_null(ops, setprocattr);
-       set_to_dummy_if_null(ops, secid_to_secctx);
-       set_to_dummy_if_null(ops, secctx_to_secid);
-       set_to_dummy_if_null(ops, release_secctx);
-#ifdef CONFIG_SECURITY_NETWORK
-       set_to_dummy_if_null(ops, unix_stream_connect);
-       set_to_dummy_if_null(ops, unix_may_send);
-       set_to_dummy_if_null(ops, socket_create);
-       set_to_dummy_if_null(ops, socket_post_create);
-       set_to_dummy_if_null(ops, socket_bind);
-       set_to_dummy_if_null(ops, socket_connect);
-       set_to_dummy_if_null(ops, socket_listen);
-       set_to_dummy_if_null(ops, socket_accept);
-       set_to_dummy_if_null(ops, socket_post_accept);
-       set_to_dummy_if_null(ops, socket_sendmsg);
-       set_to_dummy_if_null(ops, socket_recvmsg);
-       set_to_dummy_if_null(ops, socket_getsockname);
-       set_to_dummy_if_null(ops, socket_getpeername);
-       set_to_dummy_if_null(ops, socket_setsockopt);
-       set_to_dummy_if_null(ops, socket_getsockopt);
-       set_to_dummy_if_null(ops, socket_shutdown);
-       set_to_dummy_if_null(ops, socket_sock_rcv_skb);
-       set_to_dummy_if_null(ops, socket_getpeersec_stream);
-       set_to_dummy_if_null(ops, socket_getpeersec_dgram);
-       set_to_dummy_if_null(ops, sk_alloc_security);
-       set_to_dummy_if_null(ops, sk_free_security);
-       set_to_dummy_if_null(ops, sk_clone_security);
-       set_to_dummy_if_null(ops, sk_getsecid);
-       set_to_dummy_if_null(ops, sock_graft);
-       set_to_dummy_if_null(ops, inet_conn_request);
-       set_to_dummy_if_null(ops, inet_csk_clone);
-       set_to_dummy_if_null(ops, inet_conn_established);
-       set_to_dummy_if_null(ops, req_classify_flow);
- #endif        /* CONFIG_SECURITY_NETWORK */
-#ifdef  CONFIG_SECURITY_NETWORK_XFRM
-       set_to_dummy_if_null(ops, xfrm_policy_alloc_security);
-       set_to_dummy_if_null(ops, xfrm_policy_clone_security);
-       set_to_dummy_if_null(ops, xfrm_policy_free_security);
-       set_to_dummy_if_null(ops, xfrm_policy_delete_security);
-       set_to_dummy_if_null(ops, xfrm_state_alloc_security);
-       set_to_dummy_if_null(ops, xfrm_state_free_security);
-       set_to_dummy_if_null(ops, xfrm_state_delete_security);
-       set_to_dummy_if_null(ops, xfrm_policy_lookup);
-       set_to_dummy_if_null(ops, xfrm_state_pol_flow_match);
-       set_to_dummy_if_null(ops, xfrm_decode_session);
-#endif /* CONFIG_SECURITY_NETWORK_XFRM */
-#ifdef CONFIG_KEYS
-       set_to_dummy_if_null(ops, key_alloc);
-       set_to_dummy_if_null(ops, key_free);
-       set_to_dummy_if_null(ops, key_permission);
-       set_to_dummy_if_null(ops, key_getsecurity);
-#endif /* CONFIG_KEYS */
-#ifdef CONFIG_AUDIT
-       set_to_dummy_if_null(ops, audit_rule_init);
-       set_to_dummy_if_null(ops, audit_rule_known);
-       set_to_dummy_if_null(ops, audit_rule_match);
-       set_to_dummy_if_null(ops, audit_rule_free);
-#endif
-}
-
index a41cf42a4fa0b5d68921f632d329dbf5cb9d7d76..be0ebec2580b14165f24f9cbc9fac3778b73b15b 100644 (file)
@@ -28,9 +28,6 @@
 #include <linux/usb.h>
 #include <linux/moduleparam.h>
 
-/* flag to keep track of how we were registered */
-static int secondary;
-
 /* default is a generic type of usb to serial converter */
 static int vendor_id = 0x0557;
 static int product_id = 0x2008;
@@ -97,13 +94,7 @@ static int __init rootplug_init (void)
        if (register_security (&rootplug_security_ops)) {
                printk (KERN_INFO 
                        "Failure registering Root Plug module with the kernel\n");
-               /* try registering with primary module */
-               if (mod_reg_security (MY_NAME, &rootplug_security_ops)) {
-                       printk (KERN_INFO "Failure registering Root Plug "
-                               " module with primary security module.\n");
                        return -EINVAL;
-               }
-               secondary = 1;
        }
        printk (KERN_INFO "Root Plug module initialized, "
                "vendor_id = %4.4x, product id = %4.4x\n", vendor_id, product_id);
index 59838a99b80e981d27ae892e7d3aa0204bb484c1..59f23b5918b38c01028263798cebd1ca304b171d 100644 (file)
@@ -20,8 +20,8 @@
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
 
-/* things that live in dummy.c */
-extern struct security_operations dummy_security_ops;
+/* things that live in capability.c */
+extern struct security_operations default_security_ops;
 extern void security_fixup_ops(struct security_operations *ops);
 
 struct security_operations *security_ops;      /* Initialized to NULL */
@@ -57,13 +57,8 @@ int __init security_init(void)
 {
        printk(KERN_INFO "Security Framework initialized\n");
 
-       if (verify(&dummy_security_ops)) {
-               printk(KERN_ERR "%s could not verify "
-                      "dummy_security_ops structure.\n", __func__);
-               return -EIO;
-       }
-
-       security_ops = &dummy_security_ops;
+       security_fixup_ops(&default_security_ops);
+       security_ops = &default_security_ops;
        do_security_initcalls();
 
        return 0;
@@ -122,7 +117,7 @@ int register_security(struct security_operations *ops)
                return -EINVAL;
        }
 
-       if (security_ops != &dummy_security_ops)
+       if (security_ops != &default_security_ops)
                return -EAGAIN;
 
        security_ops = ops;
@@ -130,40 +125,12 @@ int register_security(struct security_operations *ops)
        return 0;
 }
 
-/**
- * mod_reg_security - allows security modules to be "stacked"
- * @name: a pointer to a string with the name of the security_options to be registered
- * @ops: a pointer to the struct security_options that is to be registered
- *
- * This function allows security modules to be stacked if the currently loaded
- * security module allows this to happen.  It passes the @name and @ops to the
- * register_security function of the currently loaded security module.
- *
- * The return value depends on the currently loaded security module, with 0 as
- * success.
- */
-int mod_reg_security(const char *name, struct security_operations *ops)
-{
-       if (verify(ops)) {
-               printk(KERN_INFO "%s could not verify "
-                      "security operations.\n", __func__);
-               return -EINVAL;
-       }
-
-       if (ops == security_ops) {
-               printk(KERN_INFO "%s security operations "
-                      "already registered.\n", __func__);
-               return -EINVAL;
-       }
-
-       return security_ops->register_security(name, ops);
-}
-
 /* Security operations */
 
-int security_ptrace(struct task_struct *parent, struct task_struct *child)
+int security_ptrace(struct task_struct *parent, struct task_struct *child,
+                   unsigned int mode)
 {
-       return security_ops->ptrace(parent, child);
+       return security_ops->ptrace(parent, child, mode);
 }
 
 int security_capget(struct task_struct *target,
@@ -291,6 +258,11 @@ int security_sb_kern_mount(struct super_block *sb, void *data)
        return security_ops->sb_kern_mount(sb, data);
 }
 
+int security_sb_show_options(struct seq_file *m, struct super_block *sb)
+{
+       return security_ops->sb_show_options(m, sb);
+}
+
 int security_sb_statfs(struct dentry *dentry)
 {
        return security_ops->sb_statfs(dentry);
@@ -342,12 +314,6 @@ void security_sb_post_pivotroot(struct path *old_path, struct path *new_path)
        security_ops->sb_post_pivotroot(old_path, new_path);
 }
 
-int security_sb_get_mnt_opts(const struct super_block *sb,
-                               struct security_mnt_opts *opts)
-{
-       return security_ops->sb_get_mnt_opts(sb, opts);
-}
-
 int security_sb_set_mnt_opts(struct super_block *sb,
                                struct security_mnt_opts *opts)
 {
@@ -894,7 +860,7 @@ EXPORT_SYMBOL(security_secctx_to_secid);
 
 void security_release_secctx(char *secdata, u32 seclen)
 {
-       return security_ops->release_secctx(secdata, seclen);
+       security_ops->release_secctx(secdata, seclen);
 }
 EXPORT_SYMBOL(security_release_secctx);
 
@@ -1011,12 +977,12 @@ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
 
 void security_sk_free(struct sock *sk)
 {
-       return security_ops->sk_free_security(sk);
+       security_ops->sk_free_security(sk);
 }
 
 void security_sk_clone(const struct sock *sk, struct sock *newsk)
 {
-       return security_ops->sk_clone_security(sk, newsk);
+       security_ops->sk_clone_security(sk, newsk);
 }
 
 void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
index 1c864c0efe2b90592d0e86a49e7347ff8ad02829..91200feb3f9c3792c2b06218a6ff44c667e168b2 100644 (file)
@@ -9,7 +9,8 @@
  *           James Morris <jmorris@redhat.com>
  *
  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
- *  Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *  Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *                                        Eric Paris <eparis@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                         <dgoeddel@trustedcs.com>
  *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
@@ -42,9 +43,7 @@
 #include <linux/fdtable.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
-#include <linux/ext2_fs.h>
 #include <linux/proc_fs.h>
-#include <linux/kd.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/tty.h>
@@ -53,7 +52,7 @@
 #include <net/tcp.h>           /* struct or_callable used in sock_rcv_skb */
 #include <net/net_namespace.h>
 #include <net/netlabel.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/ioctls.h>
 #include <asm/atomic.h>
 #include <linux/bitops.h>
@@ -104,7 +103,9 @@ int selinux_enforcing;
 
 static int __init enforcing_setup(char *str)
 {
-       selinux_enforcing = simple_strtol(str, NULL, 0);
+       unsigned long enforcing;
+       if (!strict_strtoul(str, 0, &enforcing))
+               selinux_enforcing = enforcing ? 1 : 0;
        return 1;
 }
 __setup("enforcing=", enforcing_setup);
@@ -115,7 +116,9 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
 
 static int __init selinux_enabled_setup(char *str)
 {
-       selinux_enabled = simple_strtol(str, NULL, 0);
+       unsigned long enabled;
+       if (!strict_strtoul(str, 0, &enabled))
+               selinux_enabled = enabled ? 1 : 0;
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
@@ -123,13 +126,11 @@ __setup("selinux=", selinux_enabled_setup);
 int selinux_enabled = 1;
 #endif
 
-/* Original (dummy) security module. */
-static struct security_operations *original_ops;
 
-/* Minimal support for a secondary security module,
-   just to allow the use of the dummy or capability modules.
-   The owlsm module can alternatively be used as a secondary
  module as long as CONFIG_OWLSM_FD is not enabled. */
+/*
+ * Minimal support for a secondary security module,
+ * just to allow the use of the capability module.
+ */
 static struct security_operations *secondary_ops;
 
 /* Lists of inode and superblock security structures initialized
@@ -554,13 +555,15 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        struct task_security_struct *tsec = current->security;
        struct superblock_security_struct *sbsec = sb->s_security;
        const char *name = sb->s_type->name;
-       struct inode *inode = sbsec->sb->s_root->d_inode;
-       struct inode_security_struct *root_isec = inode->i_security;
+       struct dentry *root = sb->s_root;
+       struct inode *root_inode = root->d_inode;
+       struct inode_security_struct *root_isec = root_inode->i_security;
        u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
        u32 defcontext_sid = 0;
        char **mount_options = opts->mnt_opts;
        int *flags = opts->mnt_opts_flags;
        int num_opts = opts->num_mnt_opts;
+       bool can_xattr = false;
 
        mutex_lock(&sbsec->lock);
 
@@ -594,7 +597,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
         */
        if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
            && (num_opts == 0))
-               goto out;
+               goto out;
 
        /*
         * parse the mount options, check if they are valid sids.
@@ -664,14 +667,24 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                goto out;
        }
 
-       if (strcmp(sb->s_type->name, "proc") == 0)
+       if (strcmp(name, "proc") == 0)
                sbsec->proc = 1;
 
+       /*
+        * test if the fs supports xattrs, fs_use might make use of this if the
+        * fs has no definition in policy.
+        */
+       if (root_inode->i_op->getxattr) {
+               rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
+               if (rc >= 0 || rc == -ENODATA)
+                       can_xattr = true;
+       }
+
        /* Determine the labeling behavior to use for this filesystem type. */
-       rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+       rc = security_fs_use(name, &sbsec->behavior, &sbsec->sid, can_xattr);
        if (rc) {
                printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
-                      __func__, sb->s_type->name, rc);
+                      __func__, name, rc);
                goto out;
        }
 
@@ -956,6 +969,57 @@ out_err:
        return rc;
 }
 
+void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts)
+{
+       int i;
+       char *prefix;
+
+       for (i = 0; i < opts->num_mnt_opts; i++) {
+               char *has_comma = strchr(opts->mnt_opts[i], ',');
+
+               switch (opts->mnt_opts_flags[i]) {
+               case CONTEXT_MNT:
+                       prefix = CONTEXT_STR;
+                       break;
+               case FSCONTEXT_MNT:
+                       prefix = FSCONTEXT_STR;
+                       break;
+               case ROOTCONTEXT_MNT:
+                       prefix = ROOTCONTEXT_STR;
+                       break;
+               case DEFCONTEXT_MNT:
+                       prefix = DEFCONTEXT_STR;
+                       break;
+               default:
+                       BUG();
+               };
+               /* we need a comma before each option */
+               seq_putc(m, ',');
+               seq_puts(m, prefix);
+               if (has_comma)
+                       seq_putc(m, '\"');
+               seq_puts(m, opts->mnt_opts[i]);
+               if (has_comma)
+                       seq_putc(m, '\"');
+       }
+}
+
+static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
+{
+       struct security_mnt_opts opts;
+       int rc;
+
+       rc = selinux_get_mnt_opts(sb, &opts);
+       if (rc)
+               return rc;
+
+       selinux_write_opts(m, &opts);
+
+       security_free_mnt_opts(&opts);
+
+       return rc;
+}
+
 static inline u16 inode_mode_to_security_class(umode_t mode)
 {
        switch (mode & S_IFMT) {
@@ -1682,14 +1746,23 @@ static inline u32 file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
+static int selinux_ptrace(struct task_struct *parent,
+                         struct task_struct *child,
+                         unsigned int mode)
 {
        int rc;
 
-       rc = secondary_ops->ptrace(parent, child);
+       rc = secondary_ops->ptrace(parent, child, mode);
        if (rc)
                return rc;
 
+       if (mode == PTRACE_MODE_READ) {
+               struct task_security_struct *tsec = parent->security;
+               struct task_security_struct *csec = child->security;
+               return avc_has_perm(tsec->sid, csec->sid,
+                                   SECCLASS_FILE, FILE__READ, NULL);
+       }
+
        return task_has_perm(parent, child, PROCESS__PTRACE);
 }
 
@@ -2495,7 +2568,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        }
 
        if (value && len) {
-               rc = security_sid_to_context(newsid, &context, &clen);
+               rc = security_sid_to_context_force(newsid, &context, &clen);
                if (rc) {
                        kfree(namep);
                        return rc;
@@ -2669,6 +2742,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
                return rc;
 
        rc = security_context_to_sid(value, size, &newsid);
+       if (rc == -EINVAL) {
+               if (!capable(CAP_MAC_ADMIN))
+                       return rc;
+               rc = security_context_to_sid_force(value, size, &newsid);
+       }
        if (rc)
                return rc;
 
@@ -2690,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 }
 
 static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
-                                        const void *value, size_t size,
+                                       const void *value, size_t size,
                                        int flags)
 {
        struct inode *inode = dentry->d_inode;
@@ -2703,10 +2781,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
                return;
        }
 
-       rc = security_context_to_sid(value, size, &newsid);
+       rc = security_context_to_sid_force(value, size, &newsid);
        if (rc) {
-               printk(KERN_WARNING "%s:  unable to obtain SID for context "
-                      "%s, rc=%d\n", __func__, (char *)value, -rc);
+               printk(KERN_ERR "SELinux:  unable to map context to SID"
+                      "for (%s, %lu), rc=%d\n",
+                      inode->i_sb->s_id, inode->i_ino, -rc);
                return;
        }
 
@@ -2735,9 +2814,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
 }
 
 /*
- * Copy the in-core inode security context value to the user.  If the
- * getxattr() prior to this succeeded, check to see if we need to
- * canonicalize the value to be finally returned to the user.
+ * Copy the inode security context value to the user.
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
@@ -2746,12 +2823,33 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
        u32 size;
        int error;
        char *context = NULL;
+       struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec = inode->i_security;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
-       error = security_sid_to_context(isec->sid, &context, &size);
+       /*
+        * If the caller has CAP_MAC_ADMIN, then get the raw context
+        * value even if it is not defined by current policy; otherwise,
+        * use the in-core value under current policy.
+        * Use the non-auditing forms of the permission checks since
+        * getxattr may be called by unprivileged processes commonly
+        * and lack of permission just means that we fall back to the
+        * in-core context value, not a denial.
+        */
+       error = secondary_ops->capable(current, CAP_MAC_ADMIN);
+       if (!error)
+               error = avc_has_perm_noaudit(tsec->sid, tsec->sid,
+                                            SECCLASS_CAPABILITY2,
+                                            CAPABILITY2__MAC_ADMIN,
+                                            0,
+                                            NULL);
+       if (!error)
+               error = security_sid_to_context_force(isec->sid, &context,
+                                                     &size);
+       else
+               error = security_sid_to_context(isec->sid, &context, &size);
        if (error)
                return error;
        error = size;
@@ -2865,46 +2963,16 @@ static void selinux_file_free_security(struct file *file)
 static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                              unsigned long arg)
 {
-       int error = 0;
-
-       switch (cmd) {
-       case FIONREAD:
-       /* fall through */
-       case FIBMAP:
-       /* fall through */
-       case FIGETBSZ:
-       /* fall through */
-       case EXT2_IOC_GETFLAGS:
-       /* fall through */
-       case EXT2_IOC_GETVERSION:
-               error = file_has_perm(current, file, FILE__GETATTR);
-               break;
-
-       case EXT2_IOC_SETFLAGS:
-       /* fall through */
-       case EXT2_IOC_SETVERSION:
-               error = file_has_perm(current, file, FILE__SETATTR);
-               break;
-
-       /* sys_ioctl() checks */
-       case FIONBIO:
-       /* fall through */
-       case FIOASYNC:
-               error = file_has_perm(current, file, 0);
-               break;
+       u32 av = 0;
 
-       case KDSKBENT:
-       case KDSKBSENT:
-               error = task_has_capability(current, CAP_SYS_TTY_CONFIG);
-               break;
+       if (_IOC_DIR(cmd) & _IOC_WRITE)
+               av |= FILE__WRITE;
+       if (_IOC_DIR(cmd) & _IOC_READ)
+               av |= FILE__READ;
+       if (!av)
+               av = FILE__IOCTL;
 
-       /* default case assumes that the command will go
-        * to the file's ioctl() function.
-        */
-       default:
-               error = file_has_perm(current, file, FILE__IOCTL);
-       }
-       return error;
+       return file_has_perm(current, file, av);
 }
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
@@ -3663,7 +3731,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
                struct sock *sk = sock->sk;
-               u32 sid, node_perm, addrlen;
+               u32 sid, node_perm;
 
                tsec = current->security;
                isec = SOCK_INODE(sock)->i_security;
@@ -3671,12 +3739,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
                        snum = ntohs(addr4->sin_port);
-                       addrlen = sizeof(addr4->sin_addr.s_addr);
                        addrp = (char *)&addr4->sin_addr.s_addr;
                } else {
                        addr6 = (struct sockaddr_in6 *)address;
                        snum = ntohs(addr6->sin6_port);
-                       addrlen = sizeof(addr6->sin6_addr.s6_addr);
                        addrp = (char *)&addr6->sin6_addr.s6_addr;
                }
 
@@ -5047,24 +5113,6 @@ static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
        *secid = isec->sid;
 }
 
-/* module stacking operations */
-static int selinux_register_security(const char *name, struct security_operations *ops)
-{
-       if (secondary_ops != original_ops) {
-               printk(KERN_ERR "%s:  There is already a secondary security "
-                      "module registered.\n", __func__);
-               return -EINVAL;
-       }
-
-       secondary_ops = ops;
-
-       printk(KERN_INFO "%s:  Registering secondary module %s\n",
-              __func__,
-              name);
-
-       return 0;
-}
-
 static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
 {
        if (inode)
@@ -5153,6 +5201,12 @@ static int selinux_setprocattr(struct task_struct *p,
                        size--;
                }
                error = security_context_to_sid(value, size, &sid);
+               if (error == -EINVAL && !strcmp(name, "fscreate")) {
+                       if (!capable(CAP_MAC_ADMIN))
+                               return error;
+                       error = security_context_to_sid_force(value, size,
+                                                             &sid);
+               }
                if (error)
                        return error;
        }
@@ -5186,12 +5240,12 @@ static int selinux_setprocattr(struct task_struct *p,
                        struct task_struct *g, *t;
                        struct mm_struct *mm = p->mm;
                        read_lock(&tasklist_lock);
-                       do_each_thread(g, t)
+                       do_each_thread(g, t) {
                                if (t->mm == mm && t != p) {
                                        read_unlock(&tasklist_lock);
                                        return -EPERM;
                                }
-                       while_each_thread(g, t);
+                       while_each_thread(g, t);
                        read_unlock(&tasklist_lock);
                }
 
@@ -5343,10 +5397,10 @@ static struct security_operations selinux_ops = {
        .sb_free_security =             selinux_sb_free_security,
        .sb_copy_data =                 selinux_sb_copy_data,
        .sb_kern_mount =                selinux_sb_kern_mount,
+       .sb_show_options =              selinux_sb_show_options,
        .sb_statfs =                    selinux_sb_statfs,
        .sb_mount =                     selinux_mount,
        .sb_umount =                    selinux_umount,
-       .sb_get_mnt_opts =              selinux_get_mnt_opts,
        .sb_set_mnt_opts =              selinux_set_mnt_opts,
        .sb_clone_mnt_opts =            selinux_sb_clone_mnt_opts,
        .sb_parse_opts_str =            selinux_parse_opts_str,
@@ -5378,7 +5432,7 @@ static struct security_operations selinux_ops = {
        .inode_listsecurity =           selinux_inode_listsecurity,
        .inode_need_killpriv =          selinux_inode_need_killpriv,
        .inode_killpriv =               selinux_inode_killpriv,
-       .inode_getsecid =               selinux_inode_getsecid,
+       .inode_getsecid =               selinux_inode_getsecid,
 
        .file_permission =              selinux_file_permission,
        .file_alloc_security =          selinux_file_alloc_security,
@@ -5419,7 +5473,7 @@ static struct security_operations selinux_ops = {
        .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
-       .ipc_getsecid =                 selinux_ipc_getsecid,
+       .ipc_getsecid =                 selinux_ipc_getsecid,
 
        .msg_msg_alloc_security =       selinux_msg_msg_alloc_security,
        .msg_msg_free_security =        selinux_msg_msg_free_security,
@@ -5443,8 +5497,6 @@ static struct security_operations selinux_ops = {
        .sem_semctl =                   selinux_sem_semctl,
        .sem_semop =                    selinux_sem_semop,
 
-       .register_security =            selinux_register_security,
-
        .d_instantiate =                selinux_d_instantiate,
 
        .getprocattr =                  selinux_getprocattr,
@@ -5538,7 +5590,7 @@ static __init int selinux_init(void)
                                            0, SLAB_PANIC, NULL);
        avc_init();
 
-       original_ops = secondary_ops = security_ops;
+       secondary_ops = security_ops;
        if (!secondary_ops)
                panic("SELinux: No initial security operations\n");
        if (register_security(&selinux_ops))
index 6c8b9ef15579095764c4592377128a0db5f350db..1bdf973433cc20c7d5dc74fe8172047ce965d48a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SELinux support for the Audit LSM hooks
  *
- * Most of below header was moved from include/linux/selinux.h which 
+ * Most of below header was moved from include/linux/selinux.h which
  * is released under below copyrights:
  *
  * Author: James Morris <jmorris@redhat.com>
@@ -52,7 +52,7 @@ void selinux_audit_rule_free(void *rule);
  *     -errno on failure.
  */
 int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule,
-                             struct audit_context *actx);
+                            struct audit_context *actx);
 
 /**
  *     selinux_audit_rule_known - check to see if rule contains selinux fields.
index 8e23d7a873a4a3453d77bb87b235a2ebcd137649..7b9769f5e775e1dcacd24292aa2ba43d60e38691 100644 (file)
@@ -75,13 +75,12 @@ struct avc_audit_data {
 
 /* Initialize an AVC audit data structure. */
 #define AVC_AUDIT_DATA_INIT(_d,_t) \
-        { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
+       { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
 
 /*
  * AVC statistics
  */
-struct avc_cache_stats
-{
+struct avc_cache_stats {
        unsigned int lookups;
        unsigned int hits;
        unsigned int misses;
@@ -97,8 +96,8 @@ struct avc_cache_stats
 void __init avc_init(void);
 
 void avc_audit(u32 ssid, u32 tsid,
-               u16 tclass, u32 requested,
-               struct av_decision *avd, int result, struct avc_audit_data *auditdata);
+              u16 tclass, u32 requested,
+              struct av_decision *avd, int result, struct avc_audit_data *auditdata);
 
 #define AVC_STRICT 1 /* Ignore permissive mode. */
 int avc_has_perm_noaudit(u32 ssid, u32 tsid,
@@ -107,8 +106,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         struct av_decision *avd);
 
 int avc_has_perm(u32 ssid, u32 tsid,
-                 u16 tclass, u32 requested,
-                 struct avc_audit_data *auditdata);
+                u16 tclass, u32 requested,
+                struct avc_audit_data *auditdata);
 
 u32 avc_policy_seqno(void);
 
@@ -122,7 +121,7 @@ u32 avc_policy_seqno(void);
 #define AVC_CALLBACK_AUDITDENY_DISABLE 128
 
 int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
-                                     u16 tclass, u32 perms,
+                                    u16 tclass, u32 perms,
                                     u32 *out_retained),
                     u32 events, u32 ssid, u32 tsid,
                     u16 tclass, u32 perms);
index 032c2357dad1d4cef675bfc05a5e2ebb567cee7e..91070ab874ce8b1255fadfff9f99aac0ce5bcc60 100644 (file)
@@ -44,7 +44,6 @@ struct inode_security_struct {
        u16 sclass;             /* security class of this object */
        unsigned char initialized;      /* initialization flag */
        struct mutex lock;
-       unsigned char inherit;  /* inherit SID from parent entry */
 };
 
 struct file_security_struct {
index ad30ac4273d629b37e9f93ae2cbf143db36fc4f0..44cba2e21dcf2a9e65f273be89ae970d01d78f5a 100644 (file)
@@ -93,12 +93,17 @@ int security_change_sid(u32 ssid, u32 tsid,
 int security_sid_to_context(u32 sid, char **scontext,
        u32 *scontext_len);
 
+int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
+
 int security_context_to_sid(const char *scontext, u32 scontext_len,
        u32 *out_sid);
 
 int security_context_to_sid_default(const char *scontext, u32 scontext_len,
                                    u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
 
+int security_context_to_sid_force(const char *scontext, u32 scontext_len,
+                                 u32 *sid);
+
 int security_get_user_sids(u32 callsid, char *username,
                           u32 **sids, u32 *nel);
 
@@ -131,7 +136,7 @@ int security_get_allow_unknown(void);
 #define SECURITY_FS_USE_MNTPOINT       6 /* use mountpoint labeling */
 
 int security_fs_use(const char *fstype, unsigned int *behavior,
-       u32 *sid);
+       u32 *sid, bool can_xattr);
 
 int security_genfs_sid(const char *fstype, char *name, u16 sclass,
        u32 *sid);
index b6ccd09379f15456c04e32c89dca4c5119baf128..7100072bb1b0c88f56f4b9e50a48fa675338e297 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/ipv6.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
-#include <asm/bug.h>
 
 #include "netnode.h"
 #include "objsec.h"
index 90b4cff7c350280e151d8ba6fd65fc09775c92fd..fe7fba67f19f0dd2c0b2c96c5a736ecb15bd362d 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/ipv6.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
-#include <asm/bug.h>
 
 #include "netport.h"
 #include "objsec.h"
@@ -272,7 +271,7 @@ static __init int sel_netport_init(void)
        }
 
        ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET,
-                              SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
+                              SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
        if (ret != 0)
                panic("avc_add_callback() failed, error %d\n", ret);
 
index ac1ccc13a704cfaffc87a334a03388bf7f0a2d45..69c9dccc8cf0a116beecd3b093950f5c9a33b791 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/seq_file.h>
 #include <linux/percpu.h>
 #include <linux/audit.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -57,14 +57,18 @@ int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
 
 static int __init checkreqprot_setup(char *str)
 {
-       selinux_checkreqprot = simple_strtoul(str, NULL, 0) ? 1 : 0;
+       unsigned long checkreqprot;
+       if (!strict_strtoul(str, 0, &checkreqprot))
+               selinux_checkreqprot = checkreqprot ? 1 : 0;
        return 1;
 }
 __setup("checkreqprot=", checkreqprot_setup);
 
 static int __init selinux_compat_net_setup(char *str)
 {
-       selinux_compat_net = simple_strtoul(str, NULL, 0) ? 1 : 0;
+       unsigned long compat_net;
+       if (!strict_strtoul(str, 0, &compat_net))
+               selinux_compat_net = compat_net ? 1 : 0;
        return 1;
 }
 __setup("selinux_compat_net=", selinux_compat_net_setup);
@@ -352,11 +356,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
                length = count;
 
 out1:
-
-       printk(KERN_INFO "SELinux: policy loaded with handle_unknown=%s\n",
-              (security_get_reject_unknown() ? "reject" :
-               (security_get_allow_unknown() ? "allow" : "deny")));
-
        audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
                "policy loaded auid=%u ses=%u",
                audit_get_loginuid(current),
index 9e6626362bfd3504af65120b5d1090a064fcd620..a1be97f8beea0ac0aa0fa7519801128b6eb54b62 100644 (file)
@@ -311,7 +311,7 @@ void avtab_hash_eval(struct avtab *h, char *tag)
        }
 
        printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
-              "longest chain length %d sum of chain length^2 %Lu\n",
+              "longest chain length %d sum of chain length^2 %llu\n",
               tag, h->nel, slots_used, h->nslot, max_chain_len,
               chain2_len_sum);
 }
index b9a6f7fc62fca2b0b251ccb2843f60655426c944..658c2bd17da8eb4437f306a87d37ff0195b4b731 100644 (file)
@@ -28,6 +28,8 @@ struct context {
        u32 role;
        u32 type;
        struct mls_range range;
+       char *str;      /* string representation if context cannot be mapped. */
+       u32 len;        /* length of string in bytes */
 };
 
 static inline void mls_context_init(struct context *c)
@@ -106,20 +108,43 @@ static inline void context_init(struct context *c)
 
 static inline int context_cpy(struct context *dst, struct context *src)
 {
+       int rc;
+
        dst->user = src->user;
        dst->role = src->role;
        dst->type = src->type;
-       return mls_context_cpy(dst, src);
+       if (src->str) {
+               dst->str = kstrdup(src->str, GFP_ATOMIC);
+               if (!dst->str)
+                       return -ENOMEM;
+               dst->len = src->len;
+       } else {
+               dst->str = NULL;
+               dst->len = 0;
+       }
+       rc = mls_context_cpy(dst, src);
+       if (rc) {
+               kfree(dst->str);
+               return rc;
+       }
+       return 0;
 }
 
 static inline void context_destroy(struct context *c)
 {
        c->user = c->role = c->type = 0;
+       kfree(c->str);
+       c->str = NULL;
+       c->len = 0;
        mls_context_destroy(c);
 }
 
 static inline int context_cmp(struct context *c1, struct context *c2)
 {
+       if (c1->len && c2->len)
+               return (c1->len == c2->len && !strcmp(c1->str, c2->str));
+       if (c1->len || c2->len)
+               return 0;
        return ((c1->user == c2->user) &&
                (c1->role == c2->role) &&
                (c1->type == c2->type) &&
index 8b1706b7b3ccc72dc6c373423a66f0b012fc1a39..77d745da48bb6e4c2153fc3a64852b9c08f80e51 100644 (file)
@@ -239,7 +239,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
  * Policy read-lock must be held for sidtab lookup.
  *
  */
-int mls_context_to_sid(char oldc,
+int mls_context_to_sid(struct policydb *pol,
+                      char oldc,
                       char **scontext,
                       struct context *context,
                       struct sidtab *s,
@@ -286,7 +287,7 @@ int mls_context_to_sid(char oldc,
                *p++ = 0;
 
        for (l = 0; l < 2; l++) {
-               levdatum = hashtab_search(policydb.p_levels.table, scontextp);
+               levdatum = hashtab_search(pol->p_levels.table, scontextp);
                if (!levdatum) {
                        rc = -EINVAL;
                        goto out;
@@ -311,7 +312,7 @@ int mls_context_to_sid(char oldc,
                                        *rngptr++ = 0;
                                }
 
-                               catdatum = hashtab_search(policydb.p_cats.table,
+                               catdatum = hashtab_search(pol->p_cats.table,
                                                          scontextp);
                                if (!catdatum) {
                                        rc = -EINVAL;
@@ -327,7 +328,7 @@ int mls_context_to_sid(char oldc,
                                if (rngptr) {
                                        int i;
 
-                                       rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
+                                       rngdatum = hashtab_search(pol->p_cats.table, rngptr);
                                        if (!rngdatum) {
                                                rc = -EINVAL;
                                                goto out;
@@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
        if (!tmpstr) {
                rc = -ENOMEM;
        } else {
-               rc = mls_context_to_sid(':', &tmpstr, context,
+               rc = mls_context_to_sid(&policydb, ':', &tmpstr, context,
                                        NULL, SECSID_NULL);
                kfree(freestr);
        }
@@ -436,13 +437,13 @@ int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
                struct mls_level *usercon_clr = &(usercon->range.level[1]);
 
                /* Honor the user's default level if we can */
-               if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
+               if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
                        *usercon_sen = *user_def;
-               } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
+               else if (mls_level_between(fromcon_sen, user_def, user_clr))
                        *usercon_sen = *fromcon_sen;
-               } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
+               else if (mls_level_between(fromcon_clr, user_low, user_def))
                        *usercon_sen = *user_low;
-               else
+               else
                        return -EINVAL;
 
                /* Lower the clearance of available contexts
index 0fdf6257ef6429928eed044d33d9b025ecda7b49..1276715aaa8bf3f0aac5973022f38e98388b0605 100644 (file)
@@ -30,7 +30,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c);
 int mls_range_isvalid(struct policydb *p, struct mls_range *r);
 int mls_level_isvalid(struct policydb *p, struct mls_level *l);
 
-int mls_context_to_sid(char oldc,
+int mls_context_to_sid(struct policydb *p,
+                      char oldc,
                       char **scontext,
                       struct context *context,
                       struct sidtab *s,
index 84f8cc73c7db64c9b358784a5f85e4185b6ac2e4..2391761ae42248806d92b2d2e220f5b1dd7ae6ea 100644 (file)
@@ -1478,7 +1478,8 @@ int policydb_read(struct policydb *p, void *fp)
        struct ocontext *l, *c, *newc;
        struct genfs *genfs_p, *genfs, *newgenfs;
        int i, j, rc;
-       __le32 buf[8];
+       __le32 buf[4];
+       u32 nodebuf[8];
        u32 len, len2, config, nprim, nel, nel2;
        char *policydb_str;
        struct policydb_compat_info *info;
@@ -1749,11 +1750,11 @@ int policydb_read(struct policydb *p, void *fp)
                                        goto bad;
                                break;
                        case OCON_NODE:
-                               rc = next_entry(buf, fp, sizeof(u32) * 2);
+                               rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
                                if (rc < 0)
                                        goto bad;
-                               c->u.node.addr = le32_to_cpu(buf[0]);
-                               c->u.node.mask = le32_to_cpu(buf[1]);
+                               c->u.node.addr = nodebuf[0]; /* network order */
+                               c->u.node.mask = nodebuf[1]; /* network order */
                                rc = context_read_and_validate(&c->context[0], p, fp);
                                if (rc)
                                        goto bad;
@@ -1782,13 +1783,13 @@ int policydb_read(struct policydb *p, void *fp)
                        case OCON_NODE6: {
                                int k;
 
-                               rc = next_entry(buf, fp, sizeof(u32) * 8);
+                               rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
                                if (rc < 0)
                                        goto bad;
                                for (k = 0; k < 4; k++)
-                                       c->u.node6.addr[k] = le32_to_cpu(buf[k]);
+                                       c->u.node6.addr[k] = nodebuf[k];
                                for (k = 0; k < 4; k++)
-                                       c->u.node6.mask[k] = le32_to_cpu(buf[k+4]);
+                                       c->u.node6.mask[k] = nodebuf[k+4];
                                if (context_read_and_validate(&c->context[0], p, fp))
                                        goto bad;
                                break;
index dcc2e1c4fd83df58438bfd8592da112bfaa4b28d..8e42da120101432885fa63ac1b867c6f8c227d0e 100644 (file)
@@ -71,14 +71,6 @@ int selinux_policycap_openperm;
 extern const struct selinux_class_perm selinux_class_perm;
 
 static DEFINE_RWLOCK(policy_rwlock);
-#define POLICY_RDLOCK read_lock(&policy_rwlock)
-#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
-#define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
-#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
-
-static DEFINE_MUTEX(load_mutex);
-#define LOAD_LOCK mutex_lock(&load_mutex)
-#define LOAD_UNLOCK mutex_unlock(&load_mutex)
 
 static struct sidtab sidtab;
 struct policydb policydb;
@@ -332,7 +324,7 @@ static int context_struct_compute_av(struct context *scontext,
                goto inval_class;
        if (unlikely(tclass > policydb.p_classes.nprim))
                if (tclass > kdefs->cts_len ||
-                   !kdefs->class_to_string[tclass - 1] ||
+                   !kdefs->class_to_string[tclass] ||
                    !policydb.allow_unknown)
                        goto inval_class;
 
@@ -415,9 +407,19 @@ static int context_struct_compute_av(struct context *scontext,
        return 0;
 
 inval_class:
-       printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n", __func__,
-               tclass);
-       return -EINVAL;
+       if (!tclass || tclass > kdefs->cts_len ||
+           !kdefs->class_to_string[tclass]) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "SELinux: %s:  unrecognized class %d\n",
+                              __func__, tclass);
+               return -EINVAL;
+       }
+
+       /*
+        * Known to the kernel, but not to the policy.
+        * Handle as a denial (allowed is 0).
+        */
+       return 0;
 }
 
 /*
@@ -429,7 +431,7 @@ int security_permissive_sid(u32 sid)
        u32 type;
        int rc;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        context = sidtab_search(&sidtab, sid);
        BUG_ON(!context);
@@ -441,7 +443,7 @@ int security_permissive_sid(u32 sid)
         */
        rc = ebitmap_get_bit(&policydb.permissive_map, type);
 
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -486,7 +488,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
        if (!ss_initialized)
                return 0;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        /*
         * Remap extended Netlink classes for old policy versions.
@@ -543,7 +545,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
        }
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -578,7 +580,7 @@ int security_compute_av(u32 ssid,
                return 0;
        }
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        scontext = sidtab_search(&sidtab, ssid);
        if (!scontext) {
@@ -598,7 +600,7 @@ int security_compute_av(u32 ssid,
        rc = context_struct_compute_av(scontext, tcontext, tclass,
                                       requested, avd);
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -616,6 +618,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
        *scontext = NULL;
        *scontext_len = 0;
 
+       if (context->len) {
+               *scontext_len = context->len;
+               *scontext = kstrdup(context->str, GFP_ATOMIC);
+               if (!(*scontext))
+                       return -ENOMEM;
+               return 0;
+       }
+
        /* Compute the size of the context. */
        *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
        *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
@@ -655,17 +665,8 @@ const char *security_get_initial_sid_context(u32 sid)
        return initial_sid_to_string[sid];
 }
 
-/**
- * security_sid_to_context - Obtain a context for a given SID.
- * @sid: security identifier, SID
- * @scontext: security context
- * @scontext_len: length in bytes
- *
- * Write the string representation of the context associated with @sid
- * into a dynamically allocated string of the correct size.  Set @scontext
- * to point to this string and set @scontext_len to the length of the string.
- */
-int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+static int security_sid_to_context_core(u32 sid, char **scontext,
+                                       u32 *scontext_len, int force)
 {
        struct context *context;
        int rc = 0;
@@ -692,8 +693,11 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
                rc = -EINVAL;
                goto out;
        }
-       POLICY_RDLOCK;
-       context = sidtab_search(&sidtab, sid);
+       read_lock(&policy_rwlock);
+       if (force)
+               context = sidtab_search_force(&sidtab, sid);
+       else
+               context = sidtab_search(&sidtab, sid);
        if (!context) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
                        __func__, sid);
@@ -702,59 +706,54 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
        }
        rc = context_struct_to_string(context, scontext, scontext_len);
 out_unlock:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
 out:
        return rc;
 
 }
 
-static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
-                                       u32 *sid, u32 def_sid, gfp_t gfp_flags)
+/**
+ * security_sid_to_context - Obtain a context for a given SID.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size.  Set @scontext
+ * to point to this string and set @scontext_len to the length of the string.
+ */
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+{
+       return security_sid_to_context_core(sid, scontext, scontext_len, 0);
+}
+
+int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
+{
+       return security_sid_to_context_core(sid, scontext, scontext_len, 1);
+}
+
+/*
+ * Caveat:  Mutates scontext.
+ */
+static int string_to_context_struct(struct policydb *pol,
+                                   struct sidtab *sidtabp,
+                                   char *scontext,
+                                   u32 scontext_len,
+                                   struct context *ctx,
+                                   u32 def_sid)
 {
-       char *scontext2;
-       struct context context;
        struct role_datum *role;
        struct type_datum *typdatum;
        struct user_datum *usrdatum;
        char *scontextp, *p, oldc;
        int rc = 0;
 
-       if (!ss_initialized) {
-               int i;
-
-               for (i = 1; i < SECINITSID_NUM; i++) {
-                       if (!strcmp(initial_sid_to_string[i], scontext)) {
-                               *sid = i;
-                               goto out;
-                       }
-               }
-               *sid = SECINITSID_KERNEL;
-               goto out;
-       }
-       *sid = SECSID_NULL;
-
-       /* Copy the string so that we can modify the copy as we parse it.
-          The string should already by null terminated, but we append a
-          null suffix to the copy to avoid problems with the existing
-          attr package, which doesn't view the null terminator as part
-          of the attribute value. */
-       scontext2 = kmalloc(scontext_len+1, gfp_flags);
-       if (!scontext2) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       memcpy(scontext2, scontext, scontext_len);
-       scontext2[scontext_len] = 0;
-
-       context_init(&context);
-       *sid = SECSID_NULL;
-
-       POLICY_RDLOCK;
+       context_init(ctx);
 
        /* Parse the security context. */
 
        rc = -EINVAL;
-       scontextp = (char *) scontext2;
+       scontextp = (char *) scontext;
 
        /* Extract the user. */
        p = scontextp;
@@ -762,15 +761,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
                p++;
 
        if (*p == 0)
-               goto out_unlock;
+               goto out;
 
        *p++ = 0;
 
-       usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+       usrdatum = hashtab_search(pol->p_users.table, scontextp);
        if (!usrdatum)
-               goto out_unlock;
+               goto out;
 
-       context.user = usrdatum->value;
+       ctx->user = usrdatum->value;
 
        /* Extract role. */
        scontextp = p;
@@ -778,14 +777,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
                p++;
 
        if (*p == 0)
-               goto out_unlock;
+               goto out;
 
        *p++ = 0;
 
-       role = hashtab_search(policydb.p_roles.table, scontextp);
+       role = hashtab_search(pol->p_roles.table, scontextp);
        if (!role)
-               goto out_unlock;
-       context.role = role->value;
+               goto out;
+       ctx->role = role->value;
 
        /* Extract type. */
        scontextp = p;
@@ -794,33 +793,87 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
        oldc = *p;
        *p++ = 0;
 
-       typdatum = hashtab_search(policydb.p_types.table, scontextp);
+       typdatum = hashtab_search(pol->p_types.table, scontextp);
        if (!typdatum)
-               goto out_unlock;
+               goto out;
 
-       context.type = typdatum->value;
+       ctx->type = typdatum->value;
 
-       rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+       rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
        if (rc)
-               goto out_unlock;
+               goto out;
 
-       if ((p - scontext2) < scontext_len) {
+       if ((p - scontext) < scontext_len) {
                rc = -EINVAL;
-               goto out_unlock;
+               goto out;
        }
 
        /* Check the validity of the new context. */
-       if (!policydb_context_isvalid(&policydb, &context)) {
+       if (!policydb_context_isvalid(pol, ctx)) {
                rc = -EINVAL;
-               goto out_unlock;
+               context_destroy(ctx);
+               goto out;
        }
-       /* Obtain the new sid. */
+       rc = 0;
+out:
+       return rc;
+}
+
+static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
+                                       u32 *sid, u32 def_sid, gfp_t gfp_flags,
+                                       int force)
+{
+       char *scontext2, *str = NULL;
+       struct context context;
+       int rc = 0;
+
+       if (!ss_initialized) {
+               int i;
+
+               for (i = 1; i < SECINITSID_NUM; i++) {
+                       if (!strcmp(initial_sid_to_string[i], scontext)) {
+                               *sid = i;
+                               return 0;
+                       }
+               }
+               *sid = SECINITSID_KERNEL;
+               return 0;
+       }
+       *sid = SECSID_NULL;
+
+       /* Copy the string so that we can modify the copy as we parse it. */
+       scontext2 = kmalloc(scontext_len+1, gfp_flags);
+       if (!scontext2)
+               return -ENOMEM;
+       memcpy(scontext2, scontext, scontext_len);
+       scontext2[scontext_len] = 0;
+
+       if (force) {
+               /* Save another copy for storing in uninterpreted form */
+               str = kstrdup(scontext2, gfp_flags);
+               if (!str) {
+                       kfree(scontext2);
+                       return -ENOMEM;
+               }
+       }
+
+       read_lock(&policy_rwlock);
+       rc = string_to_context_struct(&policydb, &sidtab,
+                                     scontext2, scontext_len,
+                                     &context, def_sid);
+       if (rc == -EINVAL && force) {
+               context.str = str;
+               context.len = scontext_len;
+               str = NULL;
+       } else if (rc)
+               goto out;
        rc = sidtab_context_to_sid(&sidtab, &context, sid);
-out_unlock:
-       POLICY_RDUNLOCK;
-       context_destroy(&context);
-       kfree(scontext2);
+       if (rc)
+               context_destroy(&context);
 out:
+       read_unlock(&policy_rwlock);
+       kfree(scontext2);
+       kfree(str);
        return rc;
 }
 
@@ -838,7 +891,7 @@ out:
 int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
 {
        return security_context_to_sid_core(scontext, scontext_len,
-                                           sid, SECSID_NULL, GFP_KERNEL);
+                                           sid, SECSID_NULL, GFP_KERNEL, 0);
 }
 
 /**
@@ -855,6 +908,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
  * The default SID is passed to the MLS layer to be used to allow
  * kernel labeling of the MLS field if the MLS field is not present
  * (for upgrading to MLS without full relabel).
+ * Implicitly forces adding of the context even if it cannot be mapped yet.
  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
  * memory is available, or 0 on success.
  */
@@ -862,7 +916,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
                                    u32 *sid, u32 def_sid, gfp_t gfp_flags)
 {
        return security_context_to_sid_core(scontext, scontext_len,
-                                           sid, def_sid, gfp_flags);
+                                           sid, def_sid, gfp_flags, 1);
+}
+
+int security_context_to_sid_force(const char *scontext, u32 scontext_len,
+                                 u32 *sid)
+{
+       return security_context_to_sid_core(scontext, scontext_len,
+                                           sid, SECSID_NULL, GFP_KERNEL, 1);
 }
 
 static int compute_sid_handle_invalid_context(
@@ -922,7 +983,7 @@ static int security_compute_sid(u32 ssid,
 
        context_init(&newcontext);
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        scontext = sidtab_search(&sidtab, ssid);
        if (!scontext) {
@@ -1027,7 +1088,7 @@ static int security_compute_sid(u32 ssid,
        /* Obtain the sid for the context. */
        rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
 out_unlock:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        context_destroy(&newcontext);
 out:
        return rc;
@@ -1110,6 +1171,7 @@ static int validate_classes(struct policydb *p)
        const struct selinux_class_perm *kdefs = &selinux_class_perm;
        const char *def_class, *def_perm, *pol_class;
        struct symtab *perms;
+       bool print_unknown_handle = 0;
 
        if (p->allow_unknown) {
                u32 num_classes = kdefs->cts_len;
@@ -1130,6 +1192,7 @@ static int validate_classes(struct policydb *p)
                                return -EINVAL;
                        if (p->allow_unknown)
                                p->undefined_perms[i-1] = ~0U;
+                       print_unknown_handle = 1;
                        continue;
                }
                pol_class = p->p_class_val_to_name[i-1];
@@ -1159,6 +1222,7 @@ static int validate_classes(struct policydb *p)
                                return -EINVAL;
                        if (p->allow_unknown)
                                p->undefined_perms[class_val-1] |= perm_val;
+                       print_unknown_handle = 1;
                        continue;
                }
                perdatum = hashtab_search(perms->table, def_perm);
@@ -1206,6 +1270,7 @@ static int validate_classes(struct policydb *p)
                                        return -EINVAL;
                                if (p->allow_unknown)
                                        p->undefined_perms[class_val-1] |= (1 << j);
+                               print_unknown_handle = 1;
                                continue;
                        }
                        perdatum = hashtab_search(perms->table, def_perm);
@@ -1223,6 +1288,9 @@ static int validate_classes(struct policydb *p)
                        }
                }
        }
+       if (print_unknown_handle)
+               printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
+                       (security_get_allow_unknown() ? "allowed" : "denied"));
        return 0;
 }
 
@@ -1246,9 +1314,12 @@ static inline int convert_context_handle_invalid_context(struct context *context
                char *s;
                u32 len;
 
-               context_struct_to_string(context, &s, &len);
-               printk(KERN_ERR "SELinux:  context %s is invalid\n", s);
-               kfree(s);
+               if (!context_struct_to_string(context, &s, &len)) {
+                       printk(KERN_WARNING
+                      "SELinux:  Context %s would be invalid if enforcing\n",
+                              s);
+                       kfree(s);
+               }
        }
        return rc;
 }
@@ -1280,6 +1351,37 @@ static int convert_context(u32 key,
 
        args = p;
 
+       if (c->str) {
+               struct context ctx;
+               s = kstrdup(c->str, GFP_KERNEL);
+               if (!s) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+               rc = string_to_context_struct(args->newp, NULL, s,
+                                             c->len, &ctx, SECSID_NULL);
+               kfree(s);
+               if (!rc) {
+                       printk(KERN_INFO
+                      "SELinux:  Context %s became valid (mapped).\n",
+                              c->str);
+                       /* Replace string with mapped representation. */
+                       kfree(c->str);
+                       memcpy(c, &ctx, sizeof(*c));
+                       goto out;
+               } else if (rc == -EINVAL) {
+                       /* Retain string representation for later mapping. */
+                       rc = 0;
+                       goto out;
+               } else {
+                       /* Other error condition, e.g. ENOMEM. */
+                       printk(KERN_ERR
+                      "SELinux:   Unable to map context %s, rc = %d.\n",
+                              c->str, -rc);
+                       goto out;
+               }
+       }
+
        rc = context_cpy(&oldc, c);
        if (rc)
                goto out;
@@ -1319,13 +1421,21 @@ static int convert_context(u32 key,
        }
 
        context_destroy(&oldc);
+       rc = 0;
 out:
        return rc;
 bad:
-       context_struct_to_string(&oldc, &s, &len);
+       /* Map old representation to string and save it. */
+       if (context_struct_to_string(&oldc, &s, &len))
+               return -ENOMEM;
        context_destroy(&oldc);
-       printk(KERN_ERR "SELinux:  invalidating context %s\n", s);
-       kfree(s);
+       context_destroy(c);
+       c->str = s;
+       c->len = len;
+       printk(KERN_INFO
+              "SELinux:  Context %s became invalid (unmapped).\n",
+              c->str);
+       rc = 0;
        goto out;
 }
 
@@ -1359,17 +1469,13 @@ int security_load_policy(void *data, size_t len)
        int rc = 0;
        struct policy_file file = { data, len }, *fp = &file;
 
-       LOAD_LOCK;
-
        if (!ss_initialized) {
                avtab_cache_init();
                if (policydb_read(&policydb, fp)) {
-                       LOAD_UNLOCK;
                        avtab_cache_destroy();
                        return -EINVAL;
                }
                if (policydb_load_isids(&policydb, &sidtab)) {
-                       LOAD_UNLOCK;
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
                        return -EINVAL;
@@ -1378,7 +1484,6 @@ int security_load_policy(void *data, size_t len)
                if (validate_classes(&policydb)) {
                        printk(KERN_ERR
                               "SELinux:  the definition of a class is incorrect\n");
-                       LOAD_UNLOCK;
                        sidtab_destroy(&sidtab);
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
@@ -1388,7 +1493,6 @@ int security_load_policy(void *data, size_t len)
                policydb_loaded_version = policydb.policyvers;
                ss_initialized = 1;
                seqno = ++latest_granting;
-               LOAD_UNLOCK;
                selinux_complete_init();
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
@@ -1401,12 +1505,13 @@ int security_load_policy(void *data, size_t len)
        sidtab_hash_eval(&sidtab, "sids");
 #endif
 
-       if (policydb_read(&newpolicydb, fp)) {
-               LOAD_UNLOCK;
+       if (policydb_read(&newpolicydb, fp))
                return -EINVAL;
-       }
 
-       sidtab_init(&newsidtab);
+       if (sidtab_init(&newsidtab)) {
+               policydb_destroy(&newpolicydb);
+               return -ENOMEM;
+       }
 
        /* Verify that the kernel defined classes are correct. */
        if (validate_classes(&newpolicydb)) {
@@ -1429,25 +1534,28 @@ int security_load_policy(void *data, size_t len)
                goto err;
        }
 
-       /* Convert the internal representations of contexts
-          in the new SID table and remove invalid SIDs. */
+       /*
+        * Convert the internal representations of contexts
+        * in the new SID table.
+        */
        args.oldp = &policydb;
        args.newp = &newpolicydb;
-       sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+       rc = sidtab_map(&newsidtab, convert_context, &args);
+       if (rc)
+               goto err;
 
        /* Save the old policydb and SID table to free later. */
        memcpy(&oldpolicydb, &policydb, sizeof policydb);
        sidtab_set(&oldsidtab, &sidtab);
 
        /* Install the new policydb and SID table. */
-       POLICY_WRLOCK;
+       write_lock_irq(&policy_rwlock);
        memcpy(&policydb, &newpolicydb, sizeof policydb);
        sidtab_set(&sidtab, &newsidtab);
        security_load_policycaps();
        seqno = ++latest_granting;
        policydb_loaded_version = policydb.policyvers;
-       POLICY_WRUNLOCK;
-       LOAD_UNLOCK;
+       write_unlock_irq(&policy_rwlock);
 
        /* Free the old policydb and SID table. */
        policydb_destroy(&oldpolicydb);
@@ -1461,7 +1569,6 @@ int security_load_policy(void *data, size_t len)
        return 0;
 
 err:
-       LOAD_UNLOCK;
        sidtab_destroy(&newsidtab);
        policydb_destroy(&newpolicydb);
        return rc;
@@ -1479,7 +1586,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
        struct ocontext *c;
        int rc = 0;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        c = policydb.ocontexts[OCON_PORT];
        while (c) {
@@ -1504,7 +1611,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
        }
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -1518,7 +1625,7 @@ int security_netif_sid(char *name, u32 *if_sid)
        int rc = 0;
        struct ocontext *c;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        c = policydb.ocontexts[OCON_NETIF];
        while (c) {
@@ -1545,7 +1652,7 @@ int security_netif_sid(char *name, u32 *if_sid)
                *if_sid = SECINITSID_NETIF;
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -1577,7 +1684,7 @@ int security_node_sid(u16 domain,
        int rc = 0;
        struct ocontext *c;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        switch (domain) {
        case AF_INET: {
@@ -1632,7 +1739,7 @@ int security_node_sid(u16 domain,
        }
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -1671,7 +1778,9 @@ int security_get_user_sids(u32 fromsid,
        if (!ss_initialized)
                goto out;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
+
+       context_init(&usercon);
 
        fromcon = sidtab_search(&sidtab, fromsid);
        if (!fromcon) {
@@ -1722,7 +1831,7 @@ int security_get_user_sids(u32 fromsid,
        }
 
 out_unlock:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        if (rc || !mynel) {
                kfree(mysids);
                goto out;
@@ -1775,7 +1884,7 @@ int security_genfs_sid(const char *fstype,
        while (path[0] == '/' && path[1] == '/')
                path++;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
                cmp = strcmp(fstype, genfs->fstype);
@@ -1812,7 +1921,7 @@ int security_genfs_sid(const char *fstype,
 
        *sid = c->sid[0];
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -1825,12 +1934,13 @@ out:
 int security_fs_use(
        const char *fstype,
        unsigned int *behavior,
-       u32 *sid)
+       u32 *sid,
+       bool can_xattr)
 {
        int rc = 0;
        struct ocontext *c;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        c = policydb.ocontexts[OCON_FSUSE];
        while (c) {
@@ -1839,6 +1949,7 @@ int security_fs_use(
                c = c->next;
        }
 
+       /* look for labeling behavior defined in policy */
        if (c) {
                *behavior = c->v.behavior;
                if (!c->sid[0]) {
@@ -1849,18 +1960,27 @@ int security_fs_use(
                                goto out;
                }
                *sid = c->sid[0];
+               goto out;
+       }
+
+       /* labeling behavior not in policy, use xattrs if possible */
+       if (can_xattr) {
+               *behavior = SECURITY_FS_USE_XATTR;
+               *sid = SECINITSID_FS;
+               goto out;
+       }
+
+       /* no behavior in policy and can't use xattrs, try GENFS */
+       rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
+       if (rc) {
+               *behavior = SECURITY_FS_USE_NONE;
+               rc = 0;
        } else {
-               rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
-               if (rc) {
-                       *behavior = SECURITY_FS_USE_NONE;
-                       rc = 0;
-               } else {
-                       *behavior = SECURITY_FS_USE_GENFS;
-               }
+               *behavior = SECURITY_FS_USE_GENFS;
        }
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -1868,7 +1988,7 @@ int security_get_bools(int *len, char ***names, int **values)
 {
        int i, rc = -ENOMEM;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
        *names = NULL;
        *values = NULL;
 
@@ -1898,7 +2018,7 @@ int security_get_bools(int *len, char ***names, int **values)
        }
        rc = 0;
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 err:
        if (*names) {
@@ -1916,7 +2036,7 @@ int security_set_bools(int len, int *values)
        int lenp, seqno = 0;
        struct cond_node *cur;
 
-       POLICY_WRLOCK;
+       write_lock_irq(&policy_rwlock);
 
        lenp = policydb.p_bools.nprim;
        if (len != lenp) {
@@ -1950,7 +2070,7 @@ int security_set_bools(int len, int *values)
        seqno = ++latest_granting;
 
 out:
-       POLICY_WRUNLOCK;
+       write_unlock_irq(&policy_rwlock);
        if (!rc) {
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
@@ -1964,7 +2084,7 @@ int security_get_bool_value(int bool)
        int rc = 0;
        int len;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        len = policydb.p_bools.nprim;
        if (bool >= len) {
@@ -1974,7 +2094,7 @@ int security_get_bool_value(int bool)
 
        rc = policydb.bool_val_to_struct[bool]->state;
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -2029,7 +2149,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
 
        context_init(&newcon);
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
        context1 = sidtab_search(&sidtab, sid);
        if (!context1) {
                printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
@@ -2071,7 +2191,7 @@ bad:
        }
 
 out_unlock:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        context_destroy(&newcon);
 out:
        return rc;
@@ -2128,7 +2248,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
                return 0;
        }
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
        if (!nlbl_ctx) {
@@ -2147,7 +2267,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
        rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
 
 out_slowpath:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        if (rc == 0)
                /* at present NetLabel SIDs/labels really only carry MLS
                 * information so if the MLS portion of the NetLabel SID
@@ -2177,7 +2297,7 @@ int security_get_classes(char ***classes, int *nclasses)
 {
        int rc = -ENOMEM;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        *nclasses = policydb.p_classes.nprim;
        *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC);
@@ -2194,7 +2314,7 @@ int security_get_classes(char ***classes, int *nclasses)
        }
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 
@@ -2216,7 +2336,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
        int rc = -ENOMEM, i;
        struct class_datum *match;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        match = hashtab_search(policydb.p_classes.table, class);
        if (!match) {
@@ -2244,11 +2364,11 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
                goto err;
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 
 err:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        for (i = 0; i < *nperms; i++)
                kfree((*perms)[i]);
        kfree(*perms);
@@ -2279,9 +2399,9 @@ int security_policycap_supported(unsigned int req_cap)
 {
        int rc;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
        rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
 
        return rc;
 }
@@ -2345,7 +2465,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
 
        context_init(&tmprule->au_ctxt);
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        tmprule->au_seqno = latest_granting;
 
@@ -2382,7 +2502,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
                break;
        }
 
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
 
        if (rc) {
                selinux_audit_rule_free(tmprule);
@@ -2420,7 +2540,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
 }
 
 int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
-                             struct audit_context *actx)
+                            struct audit_context *actx)
 {
        struct context *ctxt;
        struct mls_level *level;
@@ -2433,7 +2553,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
                return -ENOENT;
        }
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        if (rule->au_seqno < latest_granting) {
                audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
@@ -2527,14 +2647,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
        }
 
 out:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return match;
 }
 
 static int (*aurule_callback)(void) = audit_update_lsm_rules;
 
 static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
-                               u16 class, u32 perms, u32 *retained)
+                              u16 class, u32 perms, u32 *retained)
 {
        int err = 0;
 
@@ -2615,7 +2735,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
                return 0;
        }
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
 
        if (secattr->flags & NETLBL_SECATTR_CACHE) {
                *sid = *(u32 *)secattr->cache->data;
@@ -2660,7 +2780,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
        }
 
 netlbl_secattr_to_sid_return:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 netlbl_secattr_to_sid_return_cleanup:
        ebitmap_destroy(&ctx_new.range.level[0].cat);
@@ -2685,7 +2805,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
        if (!ss_initialized)
                return 0;
 
-       POLICY_RDLOCK;
+       read_lock(&policy_rwlock);
        ctx = sidtab_search(&sidtab, sid);
        if (ctx == NULL)
                goto netlbl_sid_to_secattr_failure;
@@ -2696,12 +2816,12 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
        rc = mls_export_netlbl_cat(ctx, secattr);
        if (rc != 0)
                goto netlbl_sid_to_secattr_failure;
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
 
        return 0;
 
 netlbl_sid_to_secattr_failure:
-       POLICY_RDUNLOCK;
+       read_unlock(&policy_rwlock);
        return rc;
 }
 #endif /* CONFIG_NETLABEL */
index 4a516ff4bcdeb2b7e77df8a88ff57546eaef58c2..a81ded10412980ea9d4b186233210fec9b696ac2 100644 (file)
 #define SIDTAB_HASH(sid) \
 (sid & SIDTAB_HASH_MASK)
 
-#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
-#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
-#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
-
 int sidtab_init(struct sidtab *s)
 {
        int i;
@@ -30,7 +26,7 @@ int sidtab_init(struct sidtab *s)
        s->nel = 0;
        s->next_sid = 1;
        s->shutdown = 0;
-       INIT_SIDTAB_LOCK(s);
+       spin_lock_init(&s->lock);
        return 0;
 }
 
@@ -86,7 +82,7 @@ out:
        return rc;
 }
 
-struct context *sidtab_search(struct sidtab *s, u32 sid)
+static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
 {
        int hvalue;
        struct sidtab_node *cur;
@@ -99,7 +95,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
        while (cur != NULL && sid > cur->sid)
                cur = cur->next;
 
-       if (cur == NULL || sid != cur->sid) {
+       if (force && cur && sid == cur->sid && cur->context.len)
+               return &cur->context;
+
+       if (cur == NULL || sid != cur->sid || cur->context.len) {
                /* Remap invalid SIDs to the unlabeled SID. */
                sid = SECINITSID_UNLABELED;
                hvalue = SIDTAB_HASH(sid);
@@ -113,6 +112,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
        return &cur->context;
 }
 
+struct context *sidtab_search(struct sidtab *s, u32 sid)
+{
+       return sidtab_search_core(s, sid, 0);
+}
+
+struct context *sidtab_search_force(struct sidtab *s, u32 sid)
+{
+       return sidtab_search_core(s, sid, 1);
+}
+
 int sidtab_map(struct sidtab *s,
               int (*apply) (u32 sid,
                             struct context *context,
@@ -138,43 +147,6 @@ out:
        return rc;
 }
 
-void sidtab_map_remove_on_error(struct sidtab *s,
-                               int (*apply) (u32 sid,
-                                             struct context *context,
-                                             void *args),
-                               void *args)
-{
-       int i, ret;
-       struct sidtab_node *last, *cur, *temp;
-
-       if (!s)
-               return;
-
-       for (i = 0; i < SIDTAB_SIZE; i++) {
-               last = NULL;
-               cur = s->htable[i];
-               while (cur != NULL) {
-                       ret = apply(cur->sid, &cur->context, args);
-                       if (ret) {
-                               if (last)
-                                       last->next = cur->next;
-                               else
-                                       s->htable[i] = cur->next;
-                               temp = cur;
-                               cur = cur->next;
-                               context_destroy(&temp->context);
-                               kfree(temp);
-                               s->nel--;
-                       } else {
-                               last = cur;
-                               cur = cur->next;
-                       }
-               }
-       }
-
-       return;
-}
-
 static inline u32 sidtab_search_context(struct sidtab *s,
                                                  struct context *context)
 {
@@ -204,7 +176,7 @@ int sidtab_context_to_sid(struct sidtab *s,
 
        sid = sidtab_search_context(s, context);
        if (!sid) {
-               SIDTAB_LOCK(s, flags);
+               spin_lock_irqsave(&s->lock, flags);
                /* Rescan now that we hold the lock. */
                sid = sidtab_search_context(s, context);
                if (sid)
@@ -215,11 +187,15 @@ int sidtab_context_to_sid(struct sidtab *s,
                        goto unlock_out;
                }
                sid = s->next_sid++;
+               if (context->len)
+                       printk(KERN_INFO
+                      "SELinux:  Context %s is not valid (left unmapped).\n",
+                              context->str);
                ret = sidtab_insert(s, sid, context);
                if (ret)
                        s->next_sid--;
 unlock_out:
-               SIDTAB_UNLOCK(s, flags);
+               spin_unlock_irqrestore(&s->lock, flags);
        }
 
        if (ret)
@@ -284,19 +260,19 @@ void sidtab_set(struct sidtab *dst, struct sidtab *src)
 {
        unsigned long flags;
 
-       SIDTAB_LOCK(src, flags);
+       spin_lock_irqsave(&src->lock, flags);
        dst->htable = src->htable;
        dst->nel = src->nel;
        dst->next_sid = src->next_sid;
        dst->shutdown = 0;
-       SIDTAB_UNLOCK(src, flags);
+       spin_unlock_irqrestore(&src->lock, flags);
 }
 
 void sidtab_shutdown(struct sidtab *s)
 {
        unsigned long flags;
 
-       SIDTAB_LOCK(s, flags);
+       spin_lock_irqsave(&s->lock, flags);
        s->shutdown = 1;
-       SIDTAB_UNLOCK(s, flags);
+       spin_unlock_irqrestore(&s->lock, flags);
 }
index 2fe9dfa3eb3a3d45dfd0dd89a40a7b924d634b9c..64ea5b1cdea4775908a871e9c728aed6be5e3e30 100644 (file)
@@ -32,6 +32,7 @@ struct sidtab {
 int sidtab_init(struct sidtab *s);
 int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
 struct context *sidtab_search(struct sidtab *s, u32 sid);
+struct context *sidtab_search_force(struct sidtab *s, u32 sid);
 
 int sidtab_map(struct sidtab *s,
               int (*apply) (u32 sid,
@@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s,
                             void *args),
               void *args);
 
-void sidtab_map_remove_on_error(struct sidtab *s,
-                               int (*apply) (u32 sid,
-                                             struct context *context,
-                                             void *args),
-                               void *args);
-
 int sidtab_context_to_sid(struct sidtab *s,
                          struct context *context,
                          u32 *sid);
index 4a09293efa007329fdc56b39f2dc5dd923d45f42..ee5a51cbc5ebdd537997978760093f11994a59cc 100644 (file)
@@ -95,11 +95,12 @@ struct inode_smack *new_inode_smack(char *smack)
  *
  * Do the capability checks, and require read and write.
  */
-static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
+static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp,
+                       unsigned int mode)
 {
        int rc;
 
-       rc = cap_ptrace(ptp, ctp);
+       rc = cap_ptrace(ptp, ctp, mode);
        if (rc != 0)
                return rc;
 
@@ -1821,27 +1822,6 @@ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
        *secid = smack_to_secid(smack);
 }
 
-/* module stacking operations */
-
-/**
- * smack_register_security - stack capability module
- * @name: module name
- * @ops: module operations - ignored
- *
- * Allow the capability module to register.
- */
-static int smack_register_security(const char *name,
-                                  struct security_operations *ops)
-{
-       if (strcmp(name, "capability") != 0)
-               return -EINVAL;
-
-       printk(KERN_INFO "%s:  Registering secondary module %s\n",
-              __func__, name);
-
-       return 0;
-}
-
 /**
  * smack_d_instantiate - Make sure the blob is correct on an inode
  * @opt_dentry: unused
@@ -2672,8 +2652,6 @@ struct security_operations smack_ops = {
        .netlink_send =                 cap_netlink_send,
        .netlink_recv =                 cap_netlink_recv,
 
-       .register_security =            smack_register_security,
-
        .d_instantiate =                smack_d_instantiate,
 
        .getprocattr =                  smack_getprocattr,
index 4247406160e7ef7c5684943a9c3065e1ec73eb9a..a37bee094eba4482c612612ae42366002e3b1134 100644 (file)
@@ -1,11 +1,9 @@
 # sound/Config.in
 #
 
-menu "Sound"
-       depends on HAS_IOMEM
-
-config SOUND
+menuconfig SOUND
        tristate "Sound card support"
+       depends on HAS_IOMEM
        help
          If you have a sound card in your computer, i.e. if it can say more
          than an occasional beep, say Y.  Be sure to have all the information
@@ -28,22 +26,22 @@ config SOUND
          and read <file:Documentation/sound/oss/README.modules>; the module
          will be called soundcore.
 
+if SOUND
+
 source "sound/oss/dmasound/Kconfig"
 
 if !M68K
 
-menu "Advanced Linux Sound Architecture"
-       depends on SOUND!=n
-
-config SND
+menuconfig SND
        tristate "Advanced Linux Sound Architecture"
-       depends on SOUND
        help
          Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture),
          the new base sound system.
 
          For more information, see <http://www.alsa-project.org/>
 
+if SND
+
 source "sound/core/Kconfig"
 
 source "sound/drivers/Kconfig"
@@ -58,9 +56,7 @@ source "sound/aoa/Kconfig"
 
 source "sound/arm/Kconfig"
 
-if SPI
 source "sound/spi/Kconfig"
-endif
 
 source "sound/mips/Kconfig"
 
@@ -80,22 +76,20 @@ source "sound/parisc/Kconfig"
 
 source "sound/soc/Kconfig"
 
-endmenu
+endif # SND
 
-menu "Open Sound System"
-       depends on SOUND!=n
-
-config SOUND_PRIME
+menuconfig SOUND_PRIME
        tristate "Open Sound System (DEPRECATED)"
-       depends on SOUND
        help
          Say 'Y' or 'M' to enable Open Sound System drivers.
 
+if SOUND_PRIME
+
 source "sound/oss/Kconfig"
 
-endmenu
+endif # SOUND_PRIME
 
-endif
+endif # !M68K
 
 config AC97_BUS
        tristate
@@ -105,4 +99,4 @@ config AC97_BUS
          sound although they're sharing the AC97 bus. Concerned drivers
          should "select" this.
 
-endmenu
+endif # SOUND
index 5d5813cec4c859a1dafd4dc2d38d45029adf91c9..c081e18b95400fac658a4821c87373d200906c05 100644 (file)
@@ -1,18 +1,17 @@
-menu "Apple Onboard Audio driver"
-       depends on SND!=n && PPC_PMAC
-
-config SND_AOA
+menuconfig SND_AOA
        tristate "Apple Onboard Audio driver"
-       depends on SND
+       depends on PPC_PMAC
        select SND_PCM
        ---help---
        This option enables the new driver for the various
        Apple Onboard Audio components.
 
+if SND_AOA
+
 source "sound/aoa/fabrics/Kconfig"
 
 source "sound/aoa/codecs/Kconfig"
 
 source "sound/aoa/soundbus/Kconfig"
 
-endmenu
+endif  # SND_AOA
index d5fbd6016e9370ebd3493dc6e37f7658eacba3da..808eb11ebacdda3c44cb8ea04534681747a21e96 100644 (file)
@@ -1,6 +1,5 @@
 config SND_AOA_ONYX
        tristate "support Onyx chip"
-       depends on SND_AOA
        select I2C
        select I2C_POWERMAC
        ---help---
@@ -10,7 +9,6 @@ config SND_AOA_ONYX
 
 #config SND_AOA_TOPAZ
 #      tristate "support Topaz chips"
-#      depends on SND_AOA
 #      ---help---
 #      This option enables support for the Topaz (CS84xx)
 #      codec chips found in the latest Apple machines,
@@ -19,7 +17,6 @@ config SND_AOA_ONYX
 
 config SND_AOA_TAS
        tristate "support TAS chips"
-       depends on SND_AOA
        select I2C
        select I2C_POWERMAC
        ---help---
@@ -29,7 +26,6 @@ config SND_AOA_TAS
 
 config SND_AOA_TOONIE
        tristate "support Toonie chip"
-       depends on SND_AOA
        ---help---
        This option enables support for the toonie codec
        found in the Mac Mini. If you have a Mac Mini and
index 50d7021ff677f5e1d578d83ff7ec3c760ea600c3..3ca475a886b1c1c0deda72295746ddf9a8ec31ea 100644 (file)
@@ -1,6 +1,5 @@
 config SND_AOA_FABRIC_LAYOUT
        tristate "layout-id fabric"
-       depends on SND_AOA
        select SND_AOA_SOUNDBUS
        select SND_AOA_SOUNDBUS_I2S
        ---help---
index 7368b7ddfe0dd88f4f11f5973d8dfa186120c6d5..839d1137b9b23ca140574699c36e8ebaa8e960e6 100644 (file)
@@ -1,6 +1,5 @@
 config SND_AOA_SOUNDBUS
        tristate "Apple Soundbus support"
-       depends on SOUND
        select SND_PCM
        ---help---
        This option enables the generic driver for the soundbus
index 2e4a5e0d16db3726755dea8c8930f35138927395..351e19ea3785ce7159fe6957abc97a1b1c963971 100644 (file)
@@ -1,11 +1,19 @@
 # ALSA ARM drivers
 
-menu "ALSA ARM devices"
-       depends on SND!=n && ARM
+menuconfig SND_ARM
+       bool "ARM sound devices"
+       depends on ARM
+       default y
+       help
+         Support for sound devices specific to ARM architectures.
+         Drivers that are implemented on ASoC can be found in
+         "ALSA for SoC audio support" section.
+
+if SND_ARM
 
 config SND_SA11XX_UDA1341
        tristate "SA11xx UDA1341TS driver (iPaq H3600)"
-       depends on ARCH_SA1100 && SND && L3
+       depends on ARCH_SA1100 && L3
        select SND_PCM
        help
          Say Y here if you have a Compaq iPaq H3x00 handheld computer
@@ -16,7 +24,7 @@ config SND_SA11XX_UDA1341
 
 config SND_ARMAACI
        tristate "ARM PrimeCell PL041 AC Link support"
-       depends on SND && ARM_AMBA
+       depends on ARM_AMBA
        select SND_PCM
        select SND_AC97_CODEC
 
@@ -26,11 +34,12 @@ config SND_PXA2XX_PCM
 
 config SND_PXA2XX_AC97
        tristate "AC97 driver for the Intel PXA2xx chip"
-       depends on ARCH_PXA && SND
+       depends on ARCH_PXA
        select SND_PXA2XX_PCM
        select SND_AC97_CODEC
        help
          Say Y or M if you want to support any AC97 codec attached to
          the PXA2xx AC97 interface.
 
-endmenu
+endif  # SND_ARM
+
index 0eff33ca0f793742b97546deea5fa03b27dab220..faeddf3ecedb871835dbae30ddf74b07d85e42ad 100644 (file)
@@ -21,8 +21,6 @@
  *                              merged HAL layer (patches from Brian)
  */
 
-/* $Id: sa11xx-uda1341.c,v 1.27 2005/12/07 09:13:42 cladisch Exp $ */
-
 /***************************************************************************************************
 *
 * To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
index a8d71c6c8e7593f1619733bc7c9635bf118d43ca..335d45ecde6a19bc0d3f12a68363c669ea405a17 100644 (file)
@@ -1,24 +1,19 @@
 # ALSA soundcard-configuration
 config SND_TIMER
        tristate
-       depends on SND
 
 config SND_PCM
        tristate
        select SND_TIMER
-       depends on SND
 
 config SND_HWDEP
        tristate
-       depends on SND
 
 config SND_RAWMIDI
        tristate
-       depends on SND
 
 config SND_SEQUENCER
        tristate "Sequencer support"
-       depends on SND
        select SND_TIMER
        help
          Say Y or M to enable MIDI sequencer and router support.  This
@@ -44,11 +39,9 @@ config SND_SEQ_DUMMY
 
 config SND_OSSEMUL
        bool
-       depends on SND
 
 config SND_MIXER_OSS
        tristate "OSS Mixer API"
-       depends on SND
        select SND_OSSEMUL
        help
          To enable OSS mixer API emulation (/dev/mixer*), say Y here
@@ -61,7 +54,6 @@ config SND_MIXER_OSS
 
 config SND_PCM_OSS
        tristate "OSS PCM (digital audio) API"
-       depends on SND
        select SND_OSSEMUL
        select SND_PCM
        help
@@ -84,7 +76,7 @@ config SND_PCM_OSS_PLUGINS
 
 config SND_SEQUENCER_OSS
        bool "OSS Sequencer API"
-       depends on SND && SND_SEQUENCER
+       depends on SND_SEQUENCER
        select SND_OSSEMUL
        help
          Say Y here to enable OSS sequencer emulation (both
@@ -98,7 +90,7 @@ config SND_SEQUENCER_OSS
 
 config SND_RTCTIMER
        tristate "RTC Timer support"
-       depends on SND && RTC
+       depends on RTC
        select SND_TIMER
        help
          Say Y here to enable RTC timer support for ALSA.  ALSA uses
@@ -123,7 +115,6 @@ config SND_SEQ_RTCTIMER_DEFAULT
 
 config SND_DYNAMIC_MINORS
        bool "Dynamic device file minor numbers"
-       depends on SND
        help
          If you say Y here, the minor numbers of ALSA device files in
          /dev/snd/ are allocated dynamically.  This allows you to have
@@ -134,7 +125,6 @@ config SND_DYNAMIC_MINORS
 
 config SND_SUPPORT_OLD_API
        bool "Support old ALSA API"
-       depends on SND
        default y
        help
          Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
@@ -142,7 +132,7 @@ config SND_SUPPORT_OLD_API
 
 config SND_VERBOSE_PROCFS
        bool "Verbose procfs contents"
-       depends on SND && PROC_FS
+       depends on PROC_FS
        default y
        help
          Say Y here to include code for verbose procfs contents (provides
@@ -151,7 +141,6 @@ config SND_VERBOSE_PROCFS
 
 config SND_VERBOSE_PRINTK
        bool "Verbose printk"
-       depends on SND
        help
          Say Y here to enable verbose log messages.  These messages
          will help to identify source file and position containing
@@ -161,16 +150,17 @@ config SND_VERBOSE_PRINTK
 
 config SND_DEBUG
        bool "Debug"
-       depends on SND
        help
          Say Y here to enable ALSA debug code.
 
-config SND_DEBUG_DETECT
-       bool "Debug detection"
+config SND_DEBUG_VERBOSE
+       bool "More verbose debug"
        depends on SND_DEBUG
        help
-         Say Y here to enable extra-verbose log messages printed when
-         detecting devices.
+         Say Y here to enable extra-verbose debugging messages.
+         
+         Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages.
+         So, say Y only if you are ready to be annoyed.
 
 config SND_PCM_XRUN_DEBUG
        bool "Enable PCM ring buffer overrun/underrun debugging"
@@ -184,4 +174,3 @@ config SND_PCM_XRUN_DEBUG
 
 config SND_VMASTER
        bool
-       depends on SND
index 01a1a5af47bb7749e90370c7ff92dbae528b6199..281b2e2ef0eac0bb4b87c4a475433a466459a98d 100644 (file)
@@ -684,7 +684,8 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
        return result;
 }
 
-int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control)
+static int snd_ctl_elem_read(struct snd_card *card,
+                            struct snd_ctl_elem_value *control)
 {
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
@@ -734,8 +735,8 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
        return result;
 }
 
-int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
-                      struct snd_ctl_elem_value *control)
+static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+                             struct snd_ctl_elem_value *control)
 {
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
index ac0573416130d56b480caf2948a88f1017ad3bb8..5c254d498ae094d452bb0c85a143f468eaedde0a 100644 (file)
@@ -46,17 +46,24 @@ static char *slots[SNDRV_CARDS];
 module_param_array(slots, charp, NULL, 0444);
 MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
 
-/* return non-zero if the given index is already reserved for another
+/* return non-zero if the given index is reserved for the given
  * module via slots option
  */
-static int module_slot_mismatch(struct module *module, int idx)
+static int module_slot_match(struct module *module, int idx)
 {
+       int match = 1;
 #ifdef MODULE
-       char *s1, *s2;
+       const char *s1, *s2;
+
        if (!module || !module->name || !slots[idx])
                return 0;
-       s1 = slots[idx];
-       s2 = module->name;
+
+       s1 = module->name;
+       s2 = slots[idx];
+       if (*s2 == '!') {
+               match = 0; /* negative match */
+               s2++;
+       }
        /* compare module name strings
         * hyphens are handled as equivalent with underscore
         */
@@ -68,12 +75,12 @@ static int module_slot_mismatch(struct module *module, int idx)
                if (c2 == '-')
                        c2 = '_';
                if (c1 != c2)
-                       return 1;
+                       return !match;
                if (!c1)
                        break;
        }
-#endif
-       return 0;
+#endif /* MODULE */
+       return match;
 }
 
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
@@ -129,7 +136,7 @@ struct snd_card *snd_card_new(int idx, const char *xid,
                         struct module *module, int extra_size)
 {
        struct snd_card *card;
-       int err;
+       int err, idx2;
 
        if (extra_size < 0)
                extra_size = 0;
@@ -144,35 +151,41 @@ struct snd_card *snd_card_new(int idx, const char *xid,
        err = 0;
        mutex_lock(&snd_card_mutex);
        if (idx < 0) {
-               int idx2;
                for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
                        /* idx == -1 == 0xffff means: take any free slot */
                        if (~snd_cards_lock & idx & 1<<idx2) {
-                               if (module_slot_mismatch(module, idx2))
-                                       continue;
-                               idx = idx2;
-                               if (idx >= snd_ecards_limit)
-                                       snd_ecards_limit = idx + 1;
-                               break;
+                               if (module_slot_match(module, idx2)) {
+                                       idx = idx2;
+                                       break;
+                               }
+                       }
+       }
+       if (idx < 0) {
+               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+                       /* idx == -1 == 0xffff means: take any free slot */
+                       if (~snd_cards_lock & idx & 1<<idx2) {
+                               if (!slots[idx2] || !*slots[idx2]) {
+                                       idx = idx2;
+                                       break;
+                               }
                        }
-       } else {
-                if (idx < snd_ecards_limit) {
-                       if (snd_cards_lock & (1 << idx))
-                               err = -EBUSY;   /* invalid */
-               } else {
-                       if (idx < SNDRV_CARDS)
-                               snd_ecards_limit = idx + 1; /* increase the limit */
-                       else
-                               err = -ENODEV;
-               }
        }
-       if (idx < 0 || err < 0) {
+       if (idx < 0)
+               err = -ENODEV;
+       else if (idx < snd_ecards_limit) {
+               if (snd_cards_lock & (1 << idx))
+                       err = -EBUSY;   /* invalid */
+       } else if (idx >= SNDRV_CARDS)
+               err = -ENODEV;
+       if (err < 0) {
                mutex_unlock(&snd_card_mutex);
                snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",
                         idx, snd_ecards_limit - 1, err);
                goto __error;
        }
        snd_cards_lock |= 1 << idx;             /* lock it */
+       if (idx >= snd_ecards_limit)
+               snd_ecards_limit = idx + 1; /* increase the limit */
        mutex_unlock(&snd_card_mutex);
        card->number = idx;
        card->module = module;
index 23b7bc02728b44ac9ad1086a827ffd3b917418ea..f5d6d8d129790d8729b82c1f7221616a7ea19f63 100644 (file)
@@ -79,68 +79,6 @@ struct snd_mem_list {
 #define snd_assert(expr, args...) /**/
 #endif
 
-/*
- *  Hacks
- */
-
-#if defined(__i386__)
-/*
- * A hack to allocate large buffers via dma_alloc_coherent()
- *
- * since dma_alloc_coherent always tries GFP_DMA when the requested
- * pci memory region is below 32bit, it happens quite often that even
- * 2 order of pages cannot be allocated.
- *
- * so in the following, we allocate at first without dma_mask, so that
- * allocation will be done without GFP_DMA.  if the area doesn't match
- * with the requested region, then realloate with the original dma_mask
- * again.
- *
- * Really, we want to move this type of thing into dma_alloc_coherent()
- * so dma_mask doesn't have to be messed with.
- */
-
-static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
-                                        dma_addr_t *dma_handle,
-                                        gfp_t flags)
-{
-       void *ret;
-       u64 dma_mask, coherent_dma_mask;
-
-       if (dev == NULL || !dev->dma_mask)
-               return dma_alloc_coherent(dev, size, dma_handle, flags);
-       dma_mask = *dev->dma_mask;
-       coherent_dma_mask = dev->coherent_dma_mask;
-       *dev->dma_mask = 0xffffffff;    /* do without masking */
-       dev->coherent_dma_mask = 0xffffffff;    /* do without masking */
-       ret = dma_alloc_coherent(dev, size, dma_handle, flags);
-       *dev->dma_mask = dma_mask;      /* restore */
-       dev->coherent_dma_mask = coherent_dma_mask;     /* restore */
-       if (ret) {
-               /* obtained address is out of range? */
-               if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) {
-                       /* reallocate with the proper mask */
-                       dma_free_coherent(dev, size, ret, *dma_handle);
-                       ret = dma_alloc_coherent(dev, size, dma_handle, flags);
-               }
-       } else {
-               /* wish to success now with the proper mask... */
-               if (dma_mask != 0xffffffffUL) {
-                       /* allocation with GFP_ATOMIC to avoid the long stall */
-                       flags &= ~GFP_KERNEL;
-                       flags |= GFP_ATOMIC;
-                       ret = dma_alloc_coherent(dev, size, dma_handle, flags);
-               }
-       }
-       return ret;
-}
-
-/* redefine dma_alloc_coherent for some architectures */
-#undef dma_alloc_coherent
-#define dma_alloc_coherent snd_dma_hack_alloc_coherent
-
-#endif /* arch */
-
 /*
  *
  *  Generic memory allocators
index 47cfa5186e34e15f4775f6c15172b136f90a3999..7a1545d2d9533f4ad53b6e1693969e34cb067965 100644 (file)
@@ -148,7 +148,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
                return NULL;
        }
        spin_unlock_irqrestore(&clients_lock, flags);
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
        if (!in_interrupt()) {
                static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
                static char card_requested[SNDRV_CARDS];
index 2f00ad28a2b73e1089df52642106aa2d4f82a8fe..05410e536a4f432c75289cdea5c1843a7bad88dd 100644 (file)
@@ -124,7 +124,7 @@ static void snd_seq_device_info(struct snd_info_entry *entry,
  * load all registered drivers (called from seq_clientmgr.c)
  */
 
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
 /* avoid auto-loading during module_init() */
 static int snd_seq_in_init;
 void snd_seq_autoload_lock(void)
@@ -140,7 +140,7 @@ void snd_seq_autoload_unlock(void)
 
 void snd_seq_device_load_drivers(void)
 {
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
        struct ops_list *ops;
 
        /* Calling request_module during module_init()
@@ -566,7 +566,5 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers);
 EXPORT_SYMBOL(snd_seq_device_new);
 EXPORT_SYMBOL(snd_seq_device_register_driver);
 EXPORT_SYMBOL(snd_seq_device_unregister_driver);
-#ifdef CONFIG_KMOD
 EXPORT_SYMBOL(snd_seq_autoload_lock);
 EXPORT_SYMBOL(snd_seq_autoload_unlock);
-#endif
index 6c8ab48c689a6bb17a6b4dd490ba26c1204e32fd..09a94953745a3835569e199e29070610638dd0c6 100644 (file)
@@ -60,14 +60,14 @@ EXPORT_SYMBOL(snd_ecards_limit);
 static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
 static DEFINE_MUTEX(sound_mutex);
 
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
 
 /**
  * snd_request_card - try to load the card module
  * @card: the card number
  *
  * Tries to load the module "snd-card-X" for the given card number
- * via KMOD.  Returns immediately if already loaded.
+ * via request_module.  Returns immediately if already loaded.
  */
 void snd_request_card(int card)
 {
@@ -92,7 +92,7 @@ static void snd_request_other(int minor)
        request_module(str);
 }
 
-#endif                         /* request_module support */
+#endif /* modular kernel */
 
 /**
  * snd_lookup_minor_data - get user data of a registered device
@@ -132,7 +132,7 @@ static int snd_open(struct inode *inode, struct file *file)
                return -ENODEV;
        mptr = snd_minors[minor];
        if (mptr == NULL) {
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
                int dev = SNDRV_MINOR_DEVICE(minor);
                if (dev == SNDRV_MINOR_CONTROL) {
                        /* /dev/aloadC? */
index 9d8184a2c2d06350f44d294fdabd3d4797c6b638..0af337efc64e282367727e965bb36c090d0afd37 100644 (file)
@@ -146,7 +146,7 @@ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
        return NULL;
 }
 
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
 
 static void snd_timer_request(struct snd_timer_id *tid)
 {
@@ -259,8 +259,8 @@ int snd_timer_open(struct snd_timer_instance **ti,
        /* open a master instance */
        mutex_lock(&register_mutex);
        timer = snd_timer_find(tid);
-#ifdef CONFIG_KMOD
-       if (timer == NULL) {
+#ifdef CONFIG_MODULES
+       if (!timer) {
                mutex_unlock(&register_mutex);
                snd_timer_request(tid);
                mutex_lock(&register_mutex);
index 602b58e3b55d198914f047c6d806871abfddd00e..255fd18b9aecc357730f16c1670706d5c5d95c1d 100644 (file)
@@ -1,15 +1,41 @@
-# ALSA generic drivers
+config SND_MPU401_UART
+        tristate
+        select SND_RAWMIDI
 
-menu "Generic devices"
-       depends on SND!=n
+config SND_OPL3_LIB
+       tristate
+       select SND_TIMER
+       select SND_HWDEP
 
+config SND_OPL4_LIB
+       tristate
+       select SND_TIMER
+       select SND_HWDEP
+
+config SND_VX_LIB
+       tristate
+       select SND_HWDEP
+       select SND_PCM
+
+config SND_AC97_CODEC
+       tristate
+       select SND_PCM
+       select AC97_BUS
+       select SND_VMASTER
+
+menuconfig SND_DRIVERS
+       bool "Generic sound devices"
+       default y
+       help
+         Support for generic sound devices.
+  
+if SND_DRIVERS
 
 config SND_PCSP
        tristate "PC-Speaker support (READ HELP!)"
        depends on PCSPKR_PLATFORM && X86_PC && HIGH_RES_TIMERS
        depends on INPUT
        depends on EXPERIMENTAL
-       depends on SND
        select SND_PCM
        help
          If you don't have a sound card in your computer, you can include a
@@ -35,33 +61,8 @@ config SND_PCSP
          Say M if you don't.
          Say Y only if you really know what you do.
 
-config SND_MPU401_UART
-        tristate
-        select SND_RAWMIDI
-
-config SND_OPL3_LIB
-       tristate
-       select SND_TIMER
-       select SND_HWDEP
-
-config SND_OPL4_LIB
-       tristate
-       select SND_TIMER
-       select SND_HWDEP
-
-config SND_VX_LIB
-       tristate
-       select SND_HWDEP
-       select SND_PCM
-
-config SND_AC97_CODEC
-       tristate
-       select SND_PCM
-       select AC97_BUS
-
 config SND_DUMMY
        tristate "Dummy (/dev/null) soundcard"
-       depends on SND
        select SND_PCM
        help
          Say Y here to include the dummy driver.  This driver does
@@ -90,7 +91,6 @@ config SND_VIRMIDI
 
 config SND_MTPAV
        tristate "MOTU MidiTimePiece AV multiport MIDI"
-       depends on SND
        select SND_RAWMIDI
        help
          To use a MOTU MidiTimePiece AV multiport MIDI adapter
@@ -102,7 +102,7 @@ config SND_MTPAV
 
 config SND_MTS64
        tristate "ESI Miditerminal 4140 driver"
-       depends on SND && PARPORT
+       depends on PARPORT
        select SND_RAWMIDI
        help
          The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with 
@@ -115,7 +115,6 @@ config SND_MTS64
 
 config SND_SERIAL_U16550
        tristate "UART16550 serial MIDI driver"
-       depends on SND
        select SND_RAWMIDI
        help
          To include support for MIDI serial port interfaces, say Y here
@@ -131,7 +130,6 @@ config SND_SERIAL_U16550
 
 config SND_MPU401
        tristate "Generic MPU-401 UART driver"
-       depends on SND
        select SND_MPU401_UART
        help
          Say Y here to include support for MIDI ports compatible with
@@ -142,7 +140,7 @@ config SND_MPU401
 
 config SND_PORTMAN2X4
        tristate "Portman 2x4 driver"
-       depends on SND && PARPORT
+       depends on PARPORT
        select SND_RAWMIDI
        help
          Say Y here to include support for Midiman Portman 2x4 parallel
@@ -153,7 +151,7 @@ config SND_PORTMAN2X4
 
 config SND_ML403_AC97CR
        tristate "Xilinx ML403 AC97 Controller Reference"
-       depends on SND && XILINX_VIRTEX
+       depends on XILINX_VIRTEX
        select SND_AC97_CODEC
        help
          Say Y here to include support for the
@@ -163,4 +161,25 @@ config SND_ML403_AC97CR
          To compile this driver as a module, choose M here: the module
          will be called snd-ml403_ac97cr.
 
-endmenu
+config SND_AC97_POWER_SAVE
+       bool "AC97 Power-Saving Mode"
+       depends on SND_AC97_CODEC && EXPERIMENTAL
+       default n
+       help
+         Say Y here to enable the aggressive power-saving support of
+         AC97 codecs.  In this mode, the power-mode is dynamically
+         controlled at each open/close.
+
+         The mode is activated by passing power_save=1 option to
+         snd-ac97-codec driver.  You can toggle it dynamically over
+         sysfs, too.
+
+config SND_AC97_POWER_SAVE_DEFAULT
+       int "Default time-out for AC97 power-save mode"
+       depends on SND_AC97_POWER_SAVE
+       default 0
+       help
+         The default time-out value in seconds for AC97 automatic
+         power-save mode.  0 means to disable the power-save mode.
+
+endif  # SND_DRIVERS
index 1dfe6948e6ffdb14d36438dad0940e520f862338..efd22e92bcedea68f2a1de780f8e2b919b3d33fe 100644 (file)
@@ -183,7 +183,7 @@ static int vx_hwdep_dsp_load(struct snd_hwdep *hw,
                kfree(fw);
                return -ENOMEM;
        }
-       if (copy_from_user(fw->data, dsp->image, dsp->length)) {
+       if (copy_from_user((void *)fw->data, dsp->image, dsp->length)) {
                free_fw(fw);
                return -EFAULT;
        }
index e57e9cbe6a0f99aa36d8090a222c91b76b555771..9c3d361accfb108e71bf2ceea04a42f0b12972dd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <asm/unaligned.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -264,10 +265,7 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
                goto __fail;
        }
        /* write default channel status bytes */
-       buf[0] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 0));
-       buf[1] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 8));
-       buf[2] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 16));
-       buf[3] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 24));
+       put_unaligned_le32(SNDRV_PCM_DEFAULT_CON_SPDIF, buf);
        memset(buf + 4, 0, 24 - 4);
        if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0)
                goto __fail;
index bfa5d2c3608bfed3d412165357a3889b4205d24e..1f4942ea141433dfef8569fa3c3f3e478688ffb7 100644 (file)
@@ -17,8 +17,6 @@
  * 2002-05-12   Tomas Kasparek  another code cleanup
  */
 
-/* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
index 2639a6ab8f2ea122425b1b8739cfad29ac73eb2c..25347a25d63cf7571a5db7bfb0309da0b1ac5181 100644 (file)
@@ -21,12 +21,17 @@ config SND_SB16_DSP
         select SND_PCM
         select SND_SB_COMMON
 
-menu "ISA devices"
-       depends on SND!=n && ISA && ISA_DMA_API
+menuconfig SND_ISA
+       bool "ISA sound devices"
+       depends on ISA && ISA_DMA_API
+       default y
+       help
+         Support for sound devices connected via the ISA bus.
+
+if SND_ISA
 
 config SND_ADLIB
        tristate "AdLib FM card"
-       depends on SND
        select SND_OPL3_LIB
        help
          Say Y here to include support for AdLib FM cards.
@@ -36,7 +41,7 @@ config SND_ADLIB
 
 config SND_AD1816A
        tristate "Analog Devices SoundPort AD1816A"
-       depends on SND && PNP && ISA
+       depends on PNP
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -50,7 +55,6 @@ config SND_AD1816A
 
 config SND_AD1848
        tristate "Generic AD1848/CS4248 driver"
-       depends on SND
        select SND_AD1848_LIB
        help
          Say Y here to include support for AD1848 (Analog Devices) or
@@ -64,7 +68,7 @@ config SND_AD1848
 
 config SND_ALS100
        tristate "Avance Logic ALS100/ALS120"
-       depends on SND && PNP && ISA
+       depends on PNP
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -78,7 +82,7 @@ config SND_ALS100
 
 config SND_AZT2320
        tristate "Aztech Systems AZT2320"
-       depends on SND && PNP && ISA
+       depends on PNP
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -92,7 +96,6 @@ config SND_AZT2320
 
 config SND_CMI8330
        tristate "C-Media CMI8330"
-       depends on SND
        select SND_AD1848_LIB
        select SND_SB16_DSP
        help
@@ -104,7 +107,6 @@ config SND_CMI8330
 
 config SND_CS4231
        tristate "Generic Cirrus Logic CS4231 driver"
-       depends on SND
        select SND_MPU401_UART
        select SND_CS4231_LIB
        help
@@ -116,7 +118,6 @@ config SND_CS4231
 
 config SND_CS4232
        tristate "Generic Cirrus Logic CS4232 driver"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_CS4231_LIB
@@ -129,7 +130,6 @@ config SND_CS4232
 
 config SND_CS4236
        tristate "Generic Cirrus Logic CS4236+ driver"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_CS4231_LIB
@@ -142,7 +142,7 @@ config SND_CS4236
 
 config SND_DT019X
        tristate "Diamond Technologies DT-019X, Avance Logic ALS-007"
-       depends on SND && PNP && ISA
+       depends on PNP
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -156,7 +156,7 @@ config SND_DT019X
 
 config SND_ES968
        tristate "Generic ESS ES968 driver"
-       depends on SND && PNP && ISA
+       depends on PNP
        select ISAPNP
        select SND_MPU401_UART
        select SND_SB8_DSP
@@ -168,7 +168,6 @@ config SND_ES968
 
 config SND_ES1688
        tristate "Generic ESS ES688/ES1688 driver"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -181,7 +180,6 @@ config SND_ES1688
 
 config SND_ES18XX
        tristate "Generic ESS ES18xx driver"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -193,7 +191,7 @@ config SND_ES18XX
 
 config SND_SC6000
        tristate "Gallant SC-6000, Audio Excel DSP 16"
-       depends on SND && HAS_IOPORT
+       depends on HAS_IOPORT
        select SND_AD1848_LIB
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -204,15 +202,10 @@ config SND_SC6000
          To compile this driver as a module, choose M here: the module
          will be called snd-sc6000.
 
-config SND_GUS_SYNTH
-       tristate
-
 config SND_GUSCLASSIC
        tristate "Gravis UltraSound Classic"
-       depends on SND
        select SND_RAWMIDI
        select SND_PCM
-       select SND_GUS_SYNTH
        help
          Say Y here to include support for Gravis UltraSound Classic
          soundcards.
@@ -222,11 +215,9 @@ config SND_GUSCLASSIC
 
 config SND_GUSEXTREME
        tristate "Gravis UltraSound Extreme"
-       depends on SND
        select SND_HWDEP
        select SND_MPU401_UART
        select SND_PCM
-       select SND_GUS_SYNTH
        help
          Say Y here to include support for Gravis UltraSound Extreme
          soundcards.
@@ -236,10 +227,8 @@ config SND_GUSEXTREME
 
 config SND_GUSMAX
        tristate "Gravis UltraSound MAX"
-       depends on SND
        select SND_RAWMIDI
        select SND_CS4231_LIB
-       select SND_GUS_SYNTH
        help
          Say Y here to include support for Gravis UltraSound MAX
          soundcards.
@@ -249,10 +238,9 @@ config SND_GUSMAX
 
 config SND_INTERWAVE
        tristate "AMD InterWave, Gravis UltraSound PnP"
-       depends on SND && PNP && ISA
+       depends on PNP
        select SND_RAWMIDI
        select SND_CS4231_LIB
-       select SND_GUS_SYNTH
        help
          Say Y here to include support for AMD InterWave based
          soundcards (Gravis UltraSound Plug & Play, STB SoundRage32,
@@ -263,10 +251,9 @@ config SND_INTERWAVE
 
 config SND_INTERWAVE_STB
        tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)"
-       depends on SND && PNP && ISA
+       depends on PNP
        select SND_RAWMIDI
        select SND_CS4231_LIB
-       select SND_GUS_SYNTH
        help
          Say Y here to include support for AMD InterWave based
          soundcards with a TEA6330T bass and treble regulator
@@ -277,7 +264,6 @@ config SND_INTERWAVE_STB
 
 config SND_OPL3SA2
        tristate "Yamaha OPL3-SA2/SA3"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_CS4231_LIB
@@ -290,7 +276,6 @@ config SND_OPL3SA2
 
 config SND_OPTI92X_AD1848
        tristate "OPTi 82C92x - AD1848"
-       depends on SND
        select SND_OPL3_LIB
        select SND_OPL4_LIB
        select SND_MPU401_UART
@@ -304,7 +289,6 @@ config SND_OPTI92X_AD1848
 
 config SND_OPTI92X_CS4231
        tristate "OPTi 82C92x - CS4231"
-       depends on SND
        select SND_OPL3_LIB
        select SND_OPL4_LIB
        select SND_MPU401_UART
@@ -318,10 +302,9 @@ config SND_OPTI92X_CS4231
 
 config SND_OPTI93X
        tristate "OPTi 82C93x"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_CS4231_LIB
        help
          Say Y here to include support for soundcards based on Opti
          82C93x chips.
@@ -331,7 +314,6 @@ config SND_OPTI93X
 
 config SND_MIRO
        tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver"
-       depends on SND
        select SND_OPL4_LIB
        select SND_CS4231_LIB
        select SND_MPU401_UART
@@ -345,7 +327,6 @@ config SND_MIRO
 
 config SND_SB8
        tristate "Sound Blaster 1.0/2.0/Pro (8-bit)"
-       depends on SND
        select SND_OPL3_LIB
        select SND_RAWMIDI
        select SND_SB8_DSP
@@ -358,7 +339,6 @@ config SND_SB8
 
 config SND_SB16
        tristate "Sound Blaster 16 (PnP)"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_SB16_DSP
@@ -371,7 +351,6 @@ config SND_SB16
 
 config SND_SBAWE
        tristate "Sound Blaster AWE (32,64) (PnP)"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_SB16_DSP
@@ -402,7 +381,6 @@ config SND_SB16_CSP_FIRMWARE_IN_KERNEL
 
 config SND_SGALAXY
        tristate "Aztech Sound Galaxy"
-       depends on SND
        select SND_AD1848_LIB
        help
          Say Y here to include support for Aztech Sound Galaxy
@@ -413,7 +391,6 @@ config SND_SGALAXY
 
 config SND_SSCAPE
        tristate "Ensoniq SoundScape PnP driver"
-       depends on SND
        select SND_HWDEP
        select SND_MPU401_UART
        select SND_CS4231_LIB
@@ -426,7 +403,6 @@ config SND_SSCAPE
 
 config SND_WAVEFRONT
        tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
-       depends on SND
        select FW_LOADER
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -448,4 +424,5 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
          you need to install the firmware files from the
          alsa-firmware package.
 
-endmenu
+endif  # SND_ISA
+
index 0aa8649e5c7f897b1c5fb283b69dcd5df5f56cfc..521db705d179f94a3edcb6963773448e0ded2f09 100644 (file)
@@ -119,6 +119,42 @@ static unsigned char snd_cs4231_original_image[32] =
        0x00,                   /* 1f/31 - cbrl */
 };
 
+static unsigned char snd_opti93x_original_image[32] =
+{
+       0x00,           /* 00/00 - l_mixout_outctrl */
+       0x00,           /* 01/01 - r_mixout_outctrl */
+       0x88,           /* 02/02 - l_cd_inctrl */
+       0x88,           /* 03/03 - r_cd_inctrl */
+       0x88,           /* 04/04 - l_a1/fm_inctrl */
+       0x88,           /* 05/05 - r_a1/fm_inctrl */
+       0x80,           /* 06/06 - l_dac_inctrl */
+       0x80,           /* 07/07 - r_dac_inctrl */
+       0x00,           /* 08/08 - ply_dataform_reg */
+       0x00,           /* 09/09 - if_conf */
+       0x00,           /* 0a/10 - pin_ctrl */
+       0x00,           /* 0b/11 - err_init_reg */
+       0x0a,           /* 0c/12 - id_reg */
+       0x00,           /* 0d/13 - reserved */
+       0x00,           /* 0e/14 - ply_upcount_reg */
+       0x00,           /* 0f/15 - ply_lowcount_reg */
+       0x88,           /* 10/16 - reserved/l_a1_inctrl */
+       0x88,           /* 11/17 - reserved/r_a1_inctrl */
+       0x88,           /* 12/18 - l_line_inctrl */
+       0x88,           /* 13/19 - r_line_inctrl */
+       0x88,           /* 14/20 - l_mic_inctrl */
+       0x88,           /* 15/21 - r_mic_inctrl */
+       0x80,           /* 16/22 - l_out_outctrl */
+       0x80,           /* 17/23 - r_out_outctrl */
+       0x00,           /* 18/24 - reserved */
+       0x00,           /* 19/25 - reserved */
+       0x00,           /* 1a/26 - reserved */
+       0x00,           /* 1b/27 - reserved */
+       0x00,           /* 1c/28 - cap_dataform_reg */
+       0x00,           /* 1d/29 - reserved */
+       0x00,           /* 1e/30 - cap_upcount_reg */
+       0x00            /* 1f/31 - cap_lowcount_reg */
+};
+
 /*
  *  Basic I/O functions
  */
@@ -895,7 +931,7 @@ static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static void snd_cs4231_overrange(struct snd_cs4231 *chip)
+void snd_cs4231_overrange(struct snd_cs4231 *chip)
 {
        unsigned long flags;
        unsigned char res;
@@ -1054,8 +1090,11 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip)
        chip->image[CS4231_IFACE_CTRL] =
            (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) |
            (chip->single_dma ? CS4231_SINGLE_DMA : 0);
-       chip->image[CS4231_ALT_FEATURE_1] = 0x80;
-       chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;
+       if (chip->hardware != CS4231_HW_OPTI93X) {
+               chip->image[CS4231_ALT_FEATURE_1] = 0x80;
+               chip->image[CS4231_ALT_FEATURE_2] =
+                       chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01;
+       }
        ptr = (unsigned char *) &chip->image;
        snd_cs4231_mce_down(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1376,6 +1415,7 @@ const char *snd_cs4231_chip_id(struct snd_cs4231 *chip)
        case CS4231_HW_INTERWAVE: return "AMD InterWave";
        case CS4231_HW_OPL3SA2: return chip->card->shortname;
        case CS4231_HW_AD1845: return "AD1845";
+       case CS4231_HW_OPTI93X: return "OPTi 93x";
        default: return "???";
        }
 }
@@ -1401,8 +1441,13 @@ static int snd_cs4231_new(struct snd_card *card,
        chip->rate_constraint = snd_cs4231_xrate;
        chip->set_playback_format = snd_cs4231_playback_format;
        chip->set_capture_format = snd_cs4231_capture_format;
-        memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image));
-        
+       if (chip->hardware == CS4231_HW_OPTI93X)
+               memcpy(&chip->image, &snd_opti93x_original_image,
+                      sizeof(snd_opti93x_original_image));
+       else
+               memcpy(&chip->image, &snd_cs4231_original_image,
+                      sizeof(snd_cs4231_original_image));
+
         *rchip = chip;
         return 0;
 }
@@ -1790,6 +1835,48 @@ CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
 CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1)
 };
                                         
+static struct snd_kcontrol_new snd_opti93x_controls[] = {
+CS4231_DOUBLE("Master Playback Switch", 0,
+             OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
+CS4231_DOUBLE("Master Playback Volume", 0,
+             OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
+CS4231_DOUBLE("PCM Playback Switch", 0,
+             CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("PCM Playback Volume", 0,
+             CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1),
+CS4231_DOUBLE("FM Playback Switch", 0,
+             CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("FM Playback Volume", 0,
+             CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1),
+CS4231_DOUBLE("Line Playback Switch", 0,
+             CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+CS4231_DOUBLE("Line Playback Volume", 0,
+             CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1),
+CS4231_DOUBLE("Mic Playback Switch", 0,
+             OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("Mic Playback Volume", 0,
+             OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1),
+CS4231_DOUBLE("Mic Boost", 0,
+             CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+CS4231_DOUBLE("CD Playback Switch", 0,
+             CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("CD Playback Volume", 0,
+             CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1),
+CS4231_DOUBLE("Aux Playback Switch", 0,
+             OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("Aux Playback Volume", 0,
+             OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1),
+CS4231_DOUBLE("Capture Volume", 0,
+             CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+{
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Source",
+       .info = snd_cs4231_info_mux,
+       .get = snd_cs4231_get_mux,
+       .put = snd_cs4231_put_mux,
+}
+};
+
 int snd_cs4231_mixer(struct snd_cs4231 *chip)
 {
        struct snd_card *card;
@@ -1802,10 +1889,22 @@ int snd_cs4231_mixer(struct snd_cs4231 *chip)
 
        strcpy(card->mixername, chip->pcm->name);
 
-       for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
-               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0)
-                       return err;
-       }
+       if (chip->hardware == CS4231_HW_OPTI93X)
+               for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
+                       err = snd_ctl_add(card,
+                                       snd_ctl_new1(&snd_opti93x_controls[idx],
+                                                    chip));
+                       if (err < 0)
+                               return err;
+               }
+       else
+               for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) {
+                       err = snd_ctl_add(card,
+                                       snd_ctl_new1(&snd_cs4231_controls[idx],
+                                                    chip));
+                       if (err < 0)
+                               return err;
+               }
        return 0;
 }
 
@@ -1815,6 +1914,7 @@ EXPORT_SYMBOL(snd_cs4236_ext_out);
 EXPORT_SYMBOL(snd_cs4236_ext_in);
 EXPORT_SYMBOL(snd_cs4231_mce_up);
 EXPORT_SYMBOL(snd_cs4231_mce_down);
+EXPORT_SYMBOL(snd_cs4231_overrange);
 EXPORT_SYMBOL(snd_cs4231_interrupt);
 EXPORT_SYMBOL(snd_cs4231_chip_id);
 EXPORT_SYMBOL(snd_cs4231_create);
index fe1afc13a01d4bdf6a373a40611f24e734788dcf..41c047e665ec7d62c6f85c25dbf45ce1441e901f 100644 (file)
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
-#ifdef CS4231
+#if defined(CS4231) || defined(OPTi93X)
 #include <sound/cs4231.h>
 #else
-#ifndef OPTi93X
 #include <sound/ad1848.h>
-#else
-#include <sound/control.h>
-#include <sound/pcm.h>
-#endif /* OPTi93X */
 #endif /* CS4231 */
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
@@ -109,7 +104,6 @@ module_param(dma2, int, 0444);
 MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
 #endif /* CS4231 || OPTi93X */
 
-#define OPTi9XX_HW_DETECT      0
 #define OPTi9XX_HW_82C928      1
 #define OPTi9XX_HW_82C929      2
 #define OPTi9XX_HW_82C924      3
@@ -123,105 +117,12 @@ MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
 
 #ifdef OPTi93X
 
-#define OPTi93X_INDEX                  0x00
-#define OPTi93X_DATA                   0x01
 #define OPTi93X_STATUS                 0x02
-#define OPTi93X_DDATA                  0x03
 #define OPTi93X_PORT(chip, r)          ((chip)->port + OPTi93X_##r)
 
-#define OPTi93X_MIXOUT_LEFT            0x00
-#define OPTi93X_MIXOUT_RIGHT           0x01
-#define OPTi93X_CD_LEFT_INPUT          0x02
-#define OPTi93X_CD_RIGHT_INPUT         0x03
-#define OPTi930_AUX_LEFT_INPUT         0x04
-#define OPTi930_AUX_RIGHT_INPUT                0x05
-#define OPTi931_FM_LEFT_INPUT          0x04
-#define OPTi931_FM_RIGHT_INPUT         0x05
-#define OPTi93X_DAC_LEFT               0x06
-#define OPTi93X_DAC_RIGHT              0x07
-#define OPTi93X_PLAY_FORMAT            0x08
-#define OPTi93X_IFACE_CONF             0x09
-#define OPTi93X_PIN_CTRL               0x0a
-#define OPTi93X_ERR_INIT               0x0b
-#define OPTi93X_ID                     0x0c
-#define OPTi93X_PLAY_UPR_CNT           0x0e
-#define OPTi93X_PLAY_LWR_CNT           0x0f
-#define OPTi931_AUX_LEFT_INPUT         0x10
-#define OPTi931_AUX_RIGHT_INPUT                0x11
-#define OPTi93X_LINE_LEFT_INPUT                0x12
-#define OPTi93X_LINE_RIGHT_INPUT       0x13
-#define OPTi93X_MIC_LEFT_INPUT         0x14
-#define OPTi93X_MIC_RIGHT_INPUT                0x15
-#define OPTi93X_OUT_LEFT               0x16
-#define OPTi93X_OUT_RIGHT              0x17
-#define OPTi93X_CAPT_FORMAT            0x1c
-#define OPTi93X_CAPT_UPR_CNT           0x1e
-#define OPTi93X_CAPT_LWR_CNT           0x1f
-
-#define OPTi93X_TRD                    0x20
-#define OPTi93X_MCE                    0x40
-#define OPTi93X_INIT                   0x80
-
-#define OPTi93X_MIXOUT_MIC_GAIN                0x20
-#define OPTi93X_MIXOUT_LINE            0x00
-#define OPTi93X_MIXOUT_CD              0x40
-#define OPTi93X_MIXOUT_MIC             0x80
-#define OPTi93X_MIXOUT_MIXER           0xc0
-
-#define OPTi93X_STEREO                 0x10
-#define OPTi93X_LINEAR_8               0x00
-#define OPTi93X_ULAW_8                 0x20
-#define OPTi93X_LINEAR_16_LIT          0x40
-#define OPTi93X_ALAW_8                 0x60
-#define OPTi93X_ADPCM_16               0xa0
-#define OPTi93X_LINEAR_16_BIG          0xc0
-
-#define OPTi93X_CAPTURE_PIO            0x80
-#define OPTi93X_PLAYBACK_PIO           0x40
-#define OPTi93X_AUTOCALIB              0x08
-#define OPTi93X_SINGLE_DMA             0x04
-#define OPTi93X_CAPTURE_ENABLE         0x02
-#define OPTi93X_PLAYBACK_ENABLE                0x01
-
-#define OPTi93X_IRQ_ENABLE             0x02
-
-#define OPTi93X_DMA_REQUEST            0x10
-#define OPTi93X_CALIB_IN_PROGRESS      0x20
-
 #define OPTi93X_IRQ_PLAYBACK           0x04
 #define OPTi93X_IRQ_CAPTURE            0x08
 
-
-struct snd_opti93x {
-       unsigned long port;
-       struct resource *res_port;
-       int irq;
-       int dma1;
-       int dma2;
-
-       struct snd_opti9xx *chip;
-       unsigned short hardware;
-       unsigned char image[32];
-
-       unsigned char mce_bit;
-       unsigned short mode;
-       int mute;
-
-       spinlock_t lock;
-
-       struct snd_card *card;
-       struct snd_pcm *pcm;
-       struct snd_pcm_substream *playback_substream;
-       struct snd_pcm_substream *capture_substream;
-       unsigned int p_dma_size;
-       unsigned int c_dma_size;
-};
-
-#define OPTi93X_MODE_NONE      0x00
-#define OPTi93X_MODE_PLAY      0x01
-#define OPTi93X_MODE_CAPTURE   0x02
-#define OPTi93X_MODE_OPEN      (OPTi93X_MODE_PLAY | OPTi93X_MODE_CAPTURE)
-
 #endif /* OPTi93X */
 
 struct snd_opti9xx {
@@ -234,6 +135,7 @@ struct snd_opti9xx {
        unsigned long mc_base_size;
 #ifdef OPTi93X
        unsigned long mc_indir_index;
+       struct snd_cs4231 *codec;
 #endif /* OPTi93X */
        unsigned long pwd_reg;
 
@@ -491,16 +393,9 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
                break;
 
 #else  /* OPTi93X */
-       case OPTi9XX_HW_82C930:
        case OPTi9XX_HW_82C931:
        case OPTi9XX_HW_82C933:
-               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
-               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
-               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
-                       (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04),
-                       0x34);
-               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf);
-               /* 
+               /*
                 * The BTC 1817DW has QS1000 wavetable which is connected
                 * to the serial digital input of the OPTI931.
                 */
@@ -510,6 +405,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
                 * or digital input signal.
                 */
                snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
+       case OPTi9XX_HW_82C930: /* FALL THROUGH */
+               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
+               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
+               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
+                       (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04),
+                       0x34);
+               snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf);
                break;
 #endif /* OPTi93X */
 
@@ -654,979 +556,23 @@ __skip_mpu:
 
 #ifdef OPTi93X
 
-static unsigned char snd_opti93x_default_image[32] =
-{
-       0x00,           /* 00/00 - l_mixout_outctrl */
-       0x00,           /* 01/01 - r_mixout_outctrl */
-       0x88,           /* 02/02 - l_cd_inctrl */
-       0x88,           /* 03/03 - r_cd_inctrl */
-       0x88,           /* 04/04 - l_a1/fm_inctrl */
-       0x88,           /* 05/05 - r_a1/fm_inctrl */
-       0x80,           /* 06/06 - l_dac_inctrl */
-       0x80,           /* 07/07 - r_dac_inctrl */
-       0x00,           /* 08/08 - ply_dataform_reg */
-       0x00,           /* 09/09 - if_conf */
-       0x00,           /* 0a/10 - pin_ctrl */
-       0x00,           /* 0b/11 - err_init_reg */
-       0x0a,           /* 0c/12 - id_reg */
-       0x00,           /* 0d/13 - reserved */
-       0x00,           /* 0e/14 - ply_upcount_reg */
-       0x00,           /* 0f/15 - ply_lowcount_reg */
-       0x88,           /* 10/16 - reserved/l_a1_inctrl */
-       0x88,           /* 11/17 - reserved/r_a1_inctrl */
-       0x88,           /* 12/18 - l_line_inctrl */
-       0x88,           /* 13/19 - r_line_inctrl */
-       0x88,           /* 14/20 - l_mic_inctrl */
-       0x88,           /* 15/21 - r_mic_inctrl */
-       0x80,           /* 16/22 - l_out_outctrl */
-       0x80,           /* 17/23 - r_out_outctrl */
-       0x00,           /* 18/24 - reserved */
-       0x00,           /* 19/25 - reserved */
-       0x00,           /* 1a/26 - reserved */
-       0x00,           /* 1b/27 - reserved */
-       0x00,           /* 1c/28 - cap_dataform_reg */
-       0x00,           /* 1d/29 - reserved */
-       0x00,           /* 1e/30 - cap_upcount_reg */
-       0x00            /* 1f/31 - cap_lowcount_reg */
-};
-
-
-static int snd_opti93x_busy_wait(struct snd_opti93x *chip)
-{
-       int timeout;
-
-       for (timeout = 250; timeout-- > 0; udelay(10))
-               if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT))
-                       return 0;
-
-       snd_printk("chip still busy.\n");
-       return -EBUSY;
-}
-
-static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg)
-{
-       snd_opti93x_busy_wait(chip);
-       outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX));
-       return inb(OPTi93X_PORT(chip, DATA));
-}
-
-static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg,
-                           unsigned char value)
-{
-       snd_opti93x_busy_wait(chip);
-       outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX));
-       outb(value, OPTi93X_PORT(chip, DATA));
-}
-
-static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg,
-                                 unsigned char value)
-{
-       snd_opti93x_out(chip, reg, chip->image[reg] = value);
-}
-
-static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg,
-                                unsigned char mask, unsigned char value)
-{
-       snd_opti93x_out_image(chip, reg,
-               (chip->image[reg] & ~mask) | (value & mask));
-}
-
-
-static void snd_opti93x_mce_up(struct snd_opti93x *chip)
-{
-       snd_opti93x_busy_wait(chip);
-
-       chip->mce_bit = OPTi93X_MCE;
-       if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE))
-               outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX));
-}
-
-static void snd_opti93x_mce_down(struct snd_opti93x *chip)
-{
-       snd_opti93x_busy_wait(chip);
-
-       chip->mce_bit = 0;
-       if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)
-               outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX));
-}
-
-#define snd_opti93x_mute_reg(chip, reg, mute)  \
-       snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]);
-
-static void snd_opti93x_mute(struct snd_opti93x *chip, int mute)
-{
-       mute = mute ? 1 : 0;
-       if (chip->mute == mute)
-               return;
-
-       chip->mute = mute;
-
-       snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute);
-       switch (chip->hardware) {
-       case OPTi9XX_HW_82C930:
-               snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute);
-               snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute);
-               break;
-       case OPTi9XX_HW_82C931:
-       case OPTi9XX_HW_82C933:
-               snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute);
-               snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute);
-               snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute);
-               snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute);
-       }
-       snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute);
-       snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute);
-}
-
-
-static unsigned int snd_opti93x_get_count(unsigned char format,
-                                         unsigned int size)
-{
-       switch (format & 0xe0) {
-       case OPTi93X_LINEAR_16_LIT:
-       case OPTi93X_LINEAR_16_BIG:
-               size >>= 1;
-               break;
-       case OPTi93X_ADPCM_16:
-               return size >> 2;
-       }
-       return (format & OPTi93X_STEREO) ? (size >> 1) : size;
-}
-
-static unsigned int rates[] = {  5512,  6615,  8000,  9600, 11025, 16000, 
-                               18900, 22050, 27428, 32000, 33075, 37800,
-                               44100, 48000 };
-#define RATES ARRAY_SIZE(rates)
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-       .count = RATES,
-       .list = rates,
-       .mask = 0,
-};
-
-static unsigned char bits[] = {  0x01,  0x0f,  0x00,  0x0e,  0x03,  0x02,
-                                0x05,  0x07,  0x04,  0x06,  0x0d,  0x09,
-                                0x0b,  0x0c};
-
-static unsigned char snd_opti93x_get_freq(unsigned int rate)
-{
-       unsigned int i;
-
-       for (i = 0; i < RATES; i++) {
-               if (rate == rates[i])
-                       return bits[i];
-       }
-       snd_BUG();
-       return bits[RATES-1];
-}
-
-static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip,
-                                           unsigned int format, int channels)
-{
-       unsigned char retval = OPTi93X_LINEAR_8;
-
-       switch (format) {
-       case SNDRV_PCM_FORMAT_MU_LAW:
-               retval = OPTi93X_ULAW_8;
-               break;
-       case SNDRV_PCM_FORMAT_A_LAW:
-               retval = OPTi93X_ALAW_8;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               retval = OPTi93X_LINEAR_16_LIT;
-               break;
-       case SNDRV_PCM_FORMAT_S16_BE:
-               retval = OPTi93X_LINEAR_16_BIG;
-               break;
-       case SNDRV_PCM_FORMAT_IMA_ADPCM:
-               retval = OPTi93X_ADPCM_16;
-       }
-       return (channels > 1) ? (retval | OPTi93X_STEREO) : retval;
-}
-
-
-static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt)
-{
-       unsigned char mask;
-
-       snd_opti93x_mute(chip, 1);
-
-       snd_opti93x_mce_up(chip);
-       mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff;
-       snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt);
-       snd_opti93x_mce_down(chip);
-
-       snd_opti93x_mute(chip, 0);
-}
-
-static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt)
-{
-       snd_opti93x_mute(chip, 1);
-
-       snd_opti93x_mce_up(chip);
-       if (!(chip->mode & OPTi93X_MODE_PLAY))
-               snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt);
-       else
-               fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0;
-       snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt);
-       snd_opti93x_mce_down(chip);
-
-       snd_opti93x_mute(chip, 0);
-}
-
-
-static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-
-       if (chip->mode & mode) {
-               spin_unlock_irqrestore(&chip->lock, flags);
-               return -EAGAIN;
-       }
-
-       if (!(chip->mode & OPTi93X_MODE_OPEN)) {
-               outb(0x00, OPTi93X_PORT(chip, STATUS));
-               snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL,
-                       OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE);
-               chip->mode = mode;
-       }
-       else
-               chip->mode |= mode;
-
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return 0;
-}
-
-static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-
-       chip->mode &= ~mode;
-       if (chip->mode & OPTi93X_MODE_OPEN) {
-               spin_unlock_irqrestore(&chip->lock, flags);
-               return;
-       }
-
-       snd_opti93x_mute(chip, 1);
-
-       outb(0, OPTi93X_PORT(chip, STATUS));
-       snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE,
-               ~OPTi93X_IRQ_ENABLE);
-
-       snd_opti93x_mce_up(chip);
-       snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00);
-       snd_opti93x_mce_down(chip);
-       chip->mode = 0;
-
-       snd_opti93x_mute(chip, 0);
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static int snd_opti93x_trigger(struct snd_pcm_substream *substream, 
-                              unsigned char what, int cmd)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_STOP:
-       {
-               unsigned int what = 0;
-               struct snd_pcm_substream *s;
-               snd_pcm_group_for_each_entry(s, substream) {
-                       if (s == chip->playback_substream) {
-                               what |= OPTi93X_PLAYBACK_ENABLE;
-                               snd_pcm_trigger_done(s, substream);
-                       } else if (s == chip->capture_substream) {
-                               what |= OPTi93X_CAPTURE_ENABLE;
-                               snd_pcm_trigger_done(s, substream);
-                       }
-               }
-               spin_lock(&chip->lock);
-               if (cmd == SNDRV_PCM_TRIGGER_START) {
-                       snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what);
-                       if (what & OPTi93X_CAPTURE_ENABLE)
-                               udelay(50);
-               } else
-                       snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00);
-               spin_unlock(&chip->lock);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       return snd_opti93x_trigger(substream,
-                                  OPTi93X_PLAYBACK_ENABLE, cmd);
-}
-
-static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       return snd_opti93x_trigger(substream,
-                                  OPTi93X_CAPTURE_ENABLE, cmd);
-}
-
-static int snd_opti93x_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *hw_params)
-{
-       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-}
-
-
-static int snd_opti93x_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_lib_free_pages(substream);
-       return 0;
-}
-
-
-static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       unsigned char format;
-       unsigned int count = snd_pcm_lib_period_bytes(substream);
-       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-
-       spin_lock_irqsave(&chip->lock, flags);
-
-       chip->p_dma_size = size;
-       snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF,
-               OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO,
-               ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO));
-
-       snd_dma_program(chip->dma1, runtime->dma_addr, size,
-               DMA_MODE_WRITE | DMA_AUTOINIT);
-
-       format = snd_opti93x_get_freq(runtime->rate);
-       format |= snd_opti93x_get_format(chip, runtime->format,
-               runtime->channels);
-       snd_opti93x_playback_format(chip, format);
-       format = chip->image[OPTi93X_PLAY_FORMAT];
-
-       count = snd_opti93x_get_count(format, count) - 1;
-       snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count);
-       snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8);
-
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return 0;
-}
-
-static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned long flags;
-       unsigned char format;
-       unsigned int count = snd_pcm_lib_period_bytes(substream);
-       unsigned int size = snd_pcm_lib_buffer_bytes(substream);
-
-       spin_lock_irqsave(&chip->lock, flags);
-
-       chip->c_dma_size = size;
-       snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF,
-               OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0);
-
-       snd_dma_program(chip->dma2, runtime->dma_addr, size,
-               DMA_MODE_READ | DMA_AUTOINIT);
-
-       format = snd_opti93x_get_freq(runtime->rate);
-       format |= snd_opti93x_get_format(chip, runtime->format,
-               runtime->channels);
-       snd_opti93x_capture_format(chip, format);
-       format = chip->image[OPTi93X_CAPT_FORMAT];
-
-       count = snd_opti93x_get_count(format, count) - 1;
-       snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count);
-       snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8);
-
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return 0;
-}
-
-static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-       size_t ptr;
-
-       if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE))
-               return 0;
-
-       ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size);
-       return bytes_to_frames(substream->runtime, ptr);
-}
-
-static snd_pcm_uframes_t snd_opti93x_capture_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-       size_t ptr;
-       
-       if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE))
-               return 0;
-
-       ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size);
-       return bytes_to_frames(substream->runtime, ptr);
-}
-
-
-static void snd_opti93x_overrange(struct snd_opti93x *chip)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&chip->lock, flags);
-
-       if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02))
-               chip->capture_substream->runtime->overrange++;
-
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
 static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
 {
-       struct snd_opti93x *codec = dev_id;
+       struct snd_cs4231 *codec = dev_id;
+       struct snd_opti9xx *chip = codec->card->private_data;
        unsigned char status;
 
-       status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11));
+       status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11));
        if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)
                snd_pcm_period_elapsed(codec->playback_substream);
        if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {
-               snd_opti93x_overrange(codec);
+               snd_cs4231_overrange(codec);
                snd_pcm_period_elapsed(codec->capture_substream);
        }
        outb(0x00, OPTi93X_PORT(codec, STATUS));
        return IRQ_HANDLED;
 }
 
-
-static struct snd_pcm_hardware snd_opti93x_playback = {
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
-       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
-                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
-       .rates =                SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
-       .rate_min =             5512,
-       .rate_max =             48000,
-       .channels_min =         1,
-       .channels_max =         2,
-       .buffer_bytes_max =     (128*1024),
-       .period_bytes_min =     64,
-       .period_bytes_max =     (128*1024),
-       .periods_min =          1,
-       .periods_max =          1024,
-       .fifo_size =            0,
-};
-
-static struct snd_pcm_hardware snd_opti93x_capture = {
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
-       .formats =              (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM |
-                                SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE),
-       .rates =                SNDRV_PCM_RATE_8000_48000,
-       .rate_min =             5512,
-       .rate_max =             48000,
-       .channels_min =         1,
-       .channels_max =         2,
-       .buffer_bytes_max =     (128*1024),
-       .period_bytes_min =     64,
-       .period_bytes_max =     (128*1024),
-       .periods_min =          1,
-       .periods_max =          1024,
-       .fifo_size =            0,
-};
-
-static int snd_opti93x_playback_open(struct snd_pcm_substream *substream)
-{
-       int error;
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0)
-               return error;
-       snd_pcm_set_sync(substream);
-       chip->playback_substream = substream;
-       runtime->hw = snd_opti93x_playback;
-       snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-       return error;
-}
-
-static int snd_opti93x_capture_open(struct snd_pcm_substream *substream)
-{
-       int error;
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0)
-               return error;
-       runtime->hw = snd_opti93x_capture;
-       snd_pcm_set_sync(substream);
-       chip->capture_substream = substream;
-       snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
-       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-       return error;
-}
-
-static int snd_opti93x_playback_close(struct snd_pcm_substream *substream)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-
-       chip->playback_substream = NULL;
-       snd_opti93x_close(chip, OPTi93X_MODE_PLAY);
-       return 0;
-}
-
-static int snd_opti93x_capture_close(struct snd_pcm_substream *substream)
-{
-       struct snd_opti93x *chip = snd_pcm_substream_chip(substream);
-
-       chip->capture_substream = NULL;
-       snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE);
-       return 0;
-}
-
-
-static void snd_opti93x_init(struct snd_opti93x *chip)
-{
-       unsigned long flags;
-       int i;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       snd_opti93x_mce_up(chip);
-
-       for (i = 0; i < 32; i++)
-               snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]);
-
-       snd_opti93x_mce_down(chip);
-       spin_unlock_irqrestore(&chip->lock, flags);
-}
-
-static int snd_opti93x_probe(struct snd_opti93x *chip)
-{
-       unsigned long flags;
-       unsigned char val;
-
-       spin_lock_irqsave(&chip->lock, flags);
-       val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f;
-       spin_unlock_irqrestore(&chip->lock, flags);
-
-       return (val == 0x0a) ? 0 : -ENODEV;
-}
-
-static int snd_opti93x_free(struct snd_opti93x *chip)
-{
-       release_and_free_resource(chip->res_port);
-       if (chip->dma1 >= 0) {
-               disable_dma(chip->dma1);
-               free_dma(chip->dma1);
-       }
-       if (chip->dma2 >= 0) {
-               disable_dma(chip->dma2);
-               free_dma(chip->dma2);
-       }
-       if (chip->irq >= 0) {
-         free_irq(chip->irq, chip);
-       }
-       kfree(chip);
-       return 0;
-}
-
-static int snd_opti93x_dev_free(struct snd_device *device)
-{
-       struct snd_opti93x *chip = device->device_data;
-       return snd_opti93x_free(chip);
-}
-
-static const char *snd_opti93x_chip_id(struct snd_opti93x *codec)
-{
-       switch (codec->hardware) {
-       case OPTi9XX_HW_82C930: return "82C930";
-       case OPTi9XX_HW_82C931: return "82C931";
-       case OPTi9XX_HW_82C933: return "82C933";
-       default:                return "???";
-       }
-}
-
-static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip,
-                             int dma1, int dma2,
-                             struct snd_opti93x **rcodec)
-{
-       static struct snd_device_ops ops = {
-               .dev_free =     snd_opti93x_dev_free,
-       };
-       int error;
-       struct snd_opti93x *codec;
-
-       *rcodec = NULL;
-       codec = kzalloc(sizeof(*codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-       codec->irq = -1;
-       codec->dma1 = -1;
-       codec->dma2 = -1;
-
-       if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) {
-               snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4);
-               snd_opti93x_free(codec);
-               return -EBUSY;
-       }
-       if (request_dma(dma1, "OPTI93x - 1")) {
-               snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1);
-               snd_opti93x_free(codec);
-               return -EBUSY;
-       }
-       codec->dma1 = chip->dma1;
-       if (request_dma(dma2, "OPTI93x - 2")) {
-               snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2);
-               snd_opti93x_free(codec);
-               return -EBUSY;
-       }
-       codec->dma2 = chip->dma2;
-
-       if (request_irq(chip->irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec)) {
-               snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
-               snd_opti93x_free(codec);
-               return -EBUSY;
-       }
-
-       codec->card = card;
-       codec->port = chip->wss_base + 4;
-       codec->irq = chip->irq;
-
-       spin_lock_init(&codec->lock);
-       codec->hardware = chip->hardware;
-       codec->chip = chip;
-
-       if ((error = snd_opti93x_probe(codec))) {
-               snd_opti93x_free(codec);
-               return error;
-       }
-
-       snd_opti93x_init(codec);
-
-       /* Register device */
-       if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) {
-               snd_opti93x_free(codec);
-               return error;
-       }
-
-       *rcodec = codec;
-       return 0;
-}
-
-static struct snd_pcm_ops snd_opti93x_playback_ops = {
-       .open =         snd_opti93x_playback_open,
-       .close =        snd_opti93x_playback_close,
-       .ioctl =        snd_pcm_lib_ioctl,
-       .hw_params =    snd_opti93x_hw_params,
-       .hw_free =      snd_opti93x_hw_free,
-       .prepare =      snd_opti93x_playback_prepare,
-       .trigger =      snd_opti93x_playback_trigger,
-       .pointer =      snd_opti93x_playback_pointer,
-};
-
-static struct snd_pcm_ops snd_opti93x_capture_ops = {
-       .open =         snd_opti93x_capture_open,
-       .close =        snd_opti93x_capture_close,
-       .ioctl =        snd_pcm_lib_ioctl,
-       .hw_params =    snd_opti93x_hw_params,
-       .hw_free =      snd_opti93x_hw_free,
-       .prepare =      snd_opti93x_capture_prepare,
-       .trigger =      snd_opti93x_capture_trigger,
-       .pointer =      snd_opti93x_capture_pointer,
-};
-
-static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm)
-{
-       int error;
-       struct snd_pcm *pcm;
-
-       if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)) < 0)
-               return error;
-
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops);
-
-       pcm->private_data = codec;
-       pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
-
-       strcpy(pcm->name, snd_opti93x_chip_id(codec));
-
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-                                             snd_dma_isa_data(),
-                                             64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024);
-
-       codec->pcm = pcm;
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
-}
-
-/*
- *  MIXER part
- */
-
-static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       static char *texts[4] = {
-               "Line1", "Aux", "Mic", "Mix"
-       };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 2;
-       uinfo->value.enumerated.items = 4;
-       if (uinfo->value.enumerated.item > 3)
-               uinfo->value.enumerated.item = 3;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int snd_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       
-       spin_lock_irqsave(&chip->lock, flags);
-       ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6;
-       ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6;
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return 0;
-}
-
-static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       unsigned short left, right;
-       int change;
-       
-       if (ucontrol->value.enumerated.item[0] > 3 ||
-           ucontrol->value.enumerated.item[1] > 3)
-               return -EINVAL;
-       left = ucontrol->value.enumerated.item[0] << 6;
-       right = ucontrol->value.enumerated.item[1] << 6;
-       spin_lock_irqsave(&chip->lock, flags);
-       left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left;
-       right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right;
-       change = left != chip->image[OPTi93X_MIXOUT_LEFT] ||
-                right != chip->image[OPTi93X_MIXOUT_RIGHT];
-       snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left);
-       snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right);
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return change;
-}
-
-#if 0
-
-#define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_opti93x_info_single, \
-  .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \
-  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
-
-static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0xff;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
-       
-       spin_lock_irqsave(&chip->lock, flags);
-       ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
-       spin_unlock_irqrestore(&chip->lock, flags);
-       if (invert)
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-       return 0;
-}
-
-static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int reg = kcontrol->private_value & 0xff;
-       int shift = (kcontrol->private_value >> 8) & 0xff;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
-       int change;
-       unsigned short val;
-       
-       val = (ucontrol->value.integer.value[0] & mask);
-       if (invert)
-               val = mask - val;
-       val <<= shift;
-       spin_lock_irqsave(&chip->lock, flags);
-       val = (chip->image[reg] & ~(mask << shift)) | val;
-       change = val != chip->image[reg];
-       snd_opti93x_out(chip, reg, val);
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return change;
-}
-
-#endif /* single */
-
-#define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
-  .info = snd_opti93x_info_double, \
-  .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \
-  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
-
-#define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \
-       do { xctl.private_value ^= 22; } while (0)
-#define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \
-       do { xctl.private_value &= ~0x0000ffff; \
-            xctl.private_value |= left_reg | (right_reg << 8); } while (0)
-
-static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-
-       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
-       return 0;
-}
-
-static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int left_reg = kcontrol->private_value & 0xff;
-       int right_reg = (kcontrol->private_value >> 8) & 0xff;
-       int shift_left = (kcontrol->private_value >> 16) & 0x07;
-       int shift_right = (kcontrol->private_value >> 19) & 0x07;
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-       int invert = (kcontrol->private_value >> 22) & 1;
-       
-       spin_lock_irqsave(&chip->lock, flags);
-       ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
-       ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
-       spin_unlock_irqrestore(&chip->lock, flags);
-       if (invert) {
-               ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-               ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
-       }
-       return 0;
-}
-
-static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol);
-       unsigned long flags;
-       int left_reg = kcontrol->private_value & 0xff;
-       int right_reg = (kcontrol->private_value >> 8) & 0xff;
-       int shift_left = (kcontrol->private_value >> 16) & 0x07;
-       int shift_right = (kcontrol->private_value >> 19) & 0x07;
-       int mask = (kcontrol->private_value >> 24) & 0xff;
-       int invert = (kcontrol->private_value >> 22) & 1;
-       int change;
-       unsigned short val1, val2;
-       
-       val1 = ucontrol->value.integer.value[0] & mask;
-       val2 = ucontrol->value.integer.value[1] & mask;
-       if (invert) {
-               val1 = mask - val1;
-               val2 = mask - val2;
-       }
-       val1 <<= shift_left;
-       val2 <<= shift_right;
-       spin_lock_irqsave(&chip->lock, flags);
-       val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
-       val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
-       change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
-       snd_opti93x_out_image(chip, left_reg, val1);
-       snd_opti93x_out_image(chip, right_reg, val2);
-       spin_unlock_irqrestore(&chip->lock, flags);
-       return change;
-}
-
-static struct snd_kcontrol_new snd_opti93x_controls[] __devinitdata = {
-OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), 
-OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1),
-OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), 
-OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), 
-OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1),
-OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1),
-OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), 
-OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0),
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Source",
-       .info = snd_opti93x_info_mux,
-       .get = snd_opti93x_get_mux,
-       .put = snd_opti93x_put_mux,
-}
-};
-                                        
-static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip)
-{
-       struct snd_card *card;
-       struct snd_kcontrol_new knew;
-       int err;
-       unsigned int idx;
-
-       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
-
-       card = chip->card;
-
-       strcpy(card->mixername, snd_opti93x_chip_id(chip));
-
-       for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) {
-               knew = snd_opti93x_controls[idx];
-               if (chip->hardware == OPTi9XX_HW_82C930) {
-                       if (strstr(knew.name, "FM"))    /* skip FM controls */
-                               continue;
-                       else if (strcmp(knew.name, "Mic Playback Volume"))
-                               OPTi93X_DOUBLE_INVERT_INVERT(knew);
-                       else if (strstr(knew.name, "Aux"))
-                               OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT);
-                       else if (strcmp(knew.name, "PCM Playback Volume"))
-                               OPTi93X_DOUBLE_INVERT_INVERT(knew);
-                       else if (strcmp(knew.name, "Master Playback Volume"))
-                               OPTi93X_DOUBLE_INVERT_INVERT(knew);
-               }
-               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0)
-                       return err;
-       }
-       return 0;
-}
-
 #endif /* OPTi93X */
 
 static int __devinit snd_card_opti9xx_detect(struct snd_card *card,
@@ -1739,8 +685,16 @@ static void snd_card_opti9xx_free(struct snd_card *card)
 {
        struct snd_opti9xx *chip = card->private_data;
         
-       if (chip)
+       if (chip) {
+#ifdef OPTi93X
+               struct snd_cs4231 *codec = chip->codec;
+               if (codec->irq > 0) {
+                       disable_irq(codec->irq);
+                       free_irq(codec->irq, codec);
+               }
+#endif
                release_and_free_resource(chip->res_mc_base);
+       }
 }
 
 static int __devinit snd_opti9xx_probe(struct snd_card *card)
@@ -1748,11 +702,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
        int error;
        struct snd_opti9xx *chip = card->private_data;
-#if defined(OPTi93X)
-       struct snd_opti93x *codec;
-#elif defined(CS4231)
+#if defined(CS4231) || defined(OPTi93X)
        struct snd_cs4231 *codec;
+#ifdef CS4231
        struct snd_timer *timer;
+#endif
 #else
        struct snd_ad1848 *codec;
 #endif
@@ -1784,26 +738,34 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
        if ((error = snd_opti9xx_configure(chip)))
                return error;
 
-#if defined(OPTi93X)
-       if ((error = snd_opti93x_create(card, chip, chip->dma1, chip->dma2, &codec)))
-               return error;
-       if ((error = snd_opti93x_pcm(codec, 0, &pcm)) < 0)
-               return error;
-       if ((error = snd_opti93x_mixer(codec)) < 0)
-               return error;
-#elif defined(CS4231)
+#if defined(CS4231) || defined(OPTi93X)
        if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1,
                                       chip->irq, chip->dma1, chip->dma2,
-                                      CS4231_HW_DETECT,
-                                      0,
+#ifdef CS4231
+                                      CS4231_HW_DETECT, 0,
+#else /* OPTi93x */
+                                      CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ,
+#endif
                                       &codec)) < 0)
                return error;
+#ifdef OPTi93X
+       chip->codec = codec;
+#endif
        if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0)
                return error;
        if ((error = snd_cs4231_mixer(codec)) < 0)
                return error;
+#ifdef CS4231
        if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0)
                return error;
+#else /* OPTI93X */
+       error = request_irq(chip->irq, snd_opti93x_interrupt,
+                           IRQF_DISABLED, DEV_NAME" - WSS", codec);
+       if (error < 0) {
+               snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq);
+               return error;
+       }
+#endif
 #else
        if ((error = snd_ad1848_create(card, chip->wss_base + 4,
                                       chip->irq, chip->dma1,
index c9d1c986d70e753f784235c26a806307a1af3598..1098a56b2f4b878898aca659d3096eafa6fd3edc 100644 (file)
@@ -34,5 +34,3 @@ ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
 endif
 obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o
-
-obj-m := $(sort $(obj-m))
index 95eeca163354b5303b89554bdeafb8053bc54fcd..0bb9b92566010875f148106c8423bf04a5b3cff8 100644 (file)
@@ -1939,7 +1939,7 @@ static int __devinit
 wavefront_download_firmware (snd_wavefront_t *dev, char *path)
 
 {
-       unsigned char *buf;
+       const unsigned char *buf;
        int len, err;
        int section_cnt_downloaded = 0;
        const struct firmware *firmware;
index 531f8ba96a71ae40d05b810cc6b42e36fe2ec165..a9823fad85c2d9ecaf0bbc2bfd0ad13d3e254796 100644 (file)
@@ -1,15 +1,34 @@
 # ALSA MIPS drivers
 
-menu "ALSA MIPS devices"
-       depends on SND!=n && MIPS
+menuconfig SND_MIPS
+       bool "MIPS sound devices"
+       depends on MIPS
+       default y
+       help
+         Support for sound devices of MIPS architectures.
+
+if SND_MIPS
+
+config SND_SGI_O2
+       tristate "SGI O2 Audio"
+       depends on SGI_IP32
+        help
+                Sound support for the SGI O2 Workstation. 
+
+config SND_SGI_HAL2
+        tristate "SGI HAL2 Audio"
+        depends on SGI_HAS_HAL2
+        help
+                Sound support for the SGI Indy and Indigo2 Workstation.
+
 
 config SND_AU1X00
        tristate "Au1x00 AC97 Port Driver"
-       depends on (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SND
+       depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500
        select SND_PCM
        select SND_AC97_CODEC
        help
          ALSA Sound driver for the Au1x00's AC97 port.
 
-endmenu
+endif  # SND_MIPS
 
index 47afed971fba6f81c7f06b841200f597e0794474..861ec0a574b46efd5315878f4666edc87d288271 100644 (file)
@@ -3,6 +3,10 @@
 #
 
 snd-au1x00-objs := au1x00.o
+snd-sgi-o2-objs := sgio2audio.o ad1843.o
+snd-sgi-hal2-objs := hal2.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o
+obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o
+obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o
diff --git a/sound/mips/ad1843.c b/sound/mips/ad1843.c
new file mode 100644 (file)
index 0000000..c624510
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ *   AD1843 low level driver
+ *
+ *   Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org>
+ *   Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ *
+ *   inspired from vwsnd.c (SGI VW audio driver)
+ *     Copyright 1999 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ad1843.h>
+
+/*
+ * AD1843 bitfield definitions.  All are named as in the AD1843 data
+ * sheet, with ad1843_ prepended and individual bit numbers removed.
+ *
+ * E.g., bits LSS0 through LSS2 become ad1843_LSS.
+ *
+ * Only the bitfields we need are defined.
+ */
+
+struct ad1843_bitfield {
+       char reg;
+       char lo_bit;
+       char nbits;
+};
+
+static const struct ad1843_bitfield
+       ad1843_PDNO   = {  0, 14,  1 }, /* Converter Power-Down Flag */
+       ad1843_INIT   = {  0, 15,  1 }, /* Clock Initialization Flag */
+       ad1843_RIG    = {  2,  0,  4 }, /* Right ADC Input Gain */
+       ad1843_RMGE   = {  2,  4,  1 }, /* Right ADC Mic Gain Enable */
+       ad1843_RSS    = {  2,  5,  3 }, /* Right ADC Source Select */
+       ad1843_LIG    = {  2,  8,  4 }, /* Left ADC Input Gain */
+       ad1843_LMGE   = {  2, 12,  1 }, /* Left ADC Mic Gain Enable */
+       ad1843_LSS    = {  2, 13,  3 }, /* Left ADC Source Select */
+       ad1843_RD2M   = {  3,  0,  5 }, /* Right DAC 2 Mix Gain/Atten */
+       ad1843_RD2MM  = {  3,  7,  1 }, /* Right DAC 2 Mix Mute */
+       ad1843_LD2M   = {  3,  8,  5 }, /* Left DAC 2 Mix Gain/Atten */
+       ad1843_LD2MM  = {  3, 15,  1 }, /* Left DAC 2 Mix Mute */
+       ad1843_RX1M   = {  4,  0,  5 }, /* Right Aux 1 Mix Gain/Atten */
+       ad1843_RX1MM  = {  4,  7,  1 }, /* Right Aux 1 Mix Mute */
+       ad1843_LX1M   = {  4,  8,  5 }, /* Left Aux 1 Mix Gain/Atten */
+       ad1843_LX1MM  = {  4, 15,  1 }, /* Left Aux 1 Mix Mute */
+       ad1843_RX2M   = {  5,  0,  5 }, /* Right Aux 2 Mix Gain/Atten */
+       ad1843_RX2MM  = {  5,  7,  1 }, /* Right Aux 2 Mix Mute */
+       ad1843_LX2M   = {  5,  8,  5 }, /* Left Aux 2 Mix Gain/Atten */
+       ad1843_LX2MM  = {  5, 15,  1 }, /* Left Aux 2 Mix Mute */
+       ad1843_RMCM   = {  7,  0,  5 }, /* Right Mic Mix Gain/Atten */
+       ad1843_RMCMM  = {  7,  7,  1 }, /* Right Mic Mix Mute */
+       ad1843_LMCM   = {  7,  8,  5 }, /* Left Mic Mix Gain/Atten */
+       ad1843_LMCMM  = {  7, 15,  1 }, /* Left Mic Mix Mute */
+       ad1843_HPOS   = {  8,  4,  1 }, /* Headphone Output Voltage Swing */
+       ad1843_HPOM   = {  8,  5,  1 }, /* Headphone Output Mute */
+       ad1843_MPOM   = {  8,  6,  1 }, /* Mono Output Mute */
+       ad1843_RDA1G  = {  9,  0,  6 }, /* Right DAC1 Analog/Digital Gain */
+       ad1843_RDA1GM = {  9,  7,  1 }, /* Right DAC1 Analog Mute */
+       ad1843_LDA1G  = {  9,  8,  6 }, /* Left DAC1 Analog/Digital Gain */
+       ad1843_LDA1GM = {  9, 15,  1 }, /* Left DAC1 Analog Mute */
+       ad1843_RDA2G  = { 10,  0,  6 }, /* Right DAC2 Analog/Digital Gain */
+       ad1843_RDA2GM = { 10,  7,  1 }, /* Right DAC2 Analog Mute */
+       ad1843_LDA2G  = { 10,  8,  6 }, /* Left DAC2 Analog/Digital Gain */
+       ad1843_LDA2GM = { 10, 15,  1 }, /* Left DAC2 Analog Mute */
+       ad1843_RDA1AM = { 11,  7,  1 }, /* Right DAC1 Digital Mute */
+       ad1843_LDA1AM = { 11, 15,  1 }, /* Left DAC1 Digital Mute */
+       ad1843_RDA2AM = { 12,  7,  1 }, /* Right DAC2 Digital Mute */
+       ad1843_LDA2AM = { 12, 15,  1 }, /* Left DAC2 Digital Mute */
+       ad1843_ADLC   = { 15,  0,  2 }, /* ADC Left Sample Rate Source */
+       ad1843_ADRC   = { 15,  2,  2 }, /* ADC Right Sample Rate Source */
+       ad1843_DA1C   = { 15,  8,  2 }, /* DAC1 Sample Rate Source */
+       ad1843_DA2C   = { 15, 10,  2 }, /* DAC2 Sample Rate Source */
+       ad1843_C1C    = { 17,  0, 16 }, /* Clock 1 Sample Rate Select */
+       ad1843_C2C    = { 20,  0, 16 }, /* Clock 2 Sample Rate Select */
+       ad1843_C3C    = { 23,  0, 16 }, /* Clock 3 Sample Rate Select */
+       ad1843_DAADL  = { 25,  4,  2 }, /* Digital ADC Left Source Select */
+       ad1843_DAADR  = { 25,  6,  2 }, /* Digital ADC Right Source Select */
+       ad1843_DAMIX  = { 25, 14,  1 }, /* DAC Digital Mix Enable */
+       ad1843_DRSFLT = { 25, 15,  1 }, /* Digital Reampler Filter Mode */
+       ad1843_ADLF   = { 26,  0,  2 }, /* ADC Left Channel Data Format */
+       ad1843_ADRF   = { 26,  2,  2 }, /* ADC Right Channel Data Format */
+       ad1843_ADTLK  = { 26,  4,  1 }, /* ADC Transmit Lock Mode Select */
+       ad1843_SCF    = { 26,  7,  1 }, /* SCLK Frequency Select */
+       ad1843_DA1F   = { 26,  8,  2 }, /* DAC1 Data Format Select */
+       ad1843_DA2F   = { 26, 10,  2 }, /* DAC2 Data Format Select */
+       ad1843_DA1SM  = { 26, 14,  1 }, /* DAC1 Stereo/Mono Mode Select */
+       ad1843_DA2SM  = { 26, 15,  1 }, /* DAC2 Stereo/Mono Mode Select */
+       ad1843_ADLEN  = { 27,  0,  1 }, /* ADC Left Channel Enable */
+       ad1843_ADREN  = { 27,  1,  1 }, /* ADC Right Channel Enable */
+       ad1843_AAMEN  = { 27,  4,  1 }, /* Analog to Analog Mix Enable */
+       ad1843_ANAEN  = { 27,  7,  1 }, /* Analog Channel Enable */
+       ad1843_DA1EN  = { 27,  8,  1 }, /* DAC1 Enable */
+       ad1843_DA2EN  = { 27,  9,  1 }, /* DAC2 Enable */
+       ad1843_DDMEN  = { 27, 12,  1 }, /* DAC2 to DAC1 Mix  Enable */
+       ad1843_C1EN   = { 28, 11,  1 }, /* Clock Generator 1 Enable */
+       ad1843_C2EN   = { 28, 12,  1 }, /* Clock Generator 2 Enable */
+       ad1843_C3EN   = { 28, 13,  1 }, /* Clock Generator 3 Enable */
+       ad1843_PDNI   = { 28, 15,  1 }; /* Converter Power Down */
+
+/*
+ * The various registers of the AD1843 use three different formats for
+ * specifying gain.  The ad1843_gain structure parameterizes the
+ * formats.
+ */
+
+struct ad1843_gain {
+       int     negative;               /* nonzero if gain is negative. */
+       const struct ad1843_bitfield *lfield;
+       const struct ad1843_bitfield *rfield;
+       const struct ad1843_bitfield *lmute;
+       const struct ad1843_bitfield *rmute;
+};
+
+static const struct ad1843_gain ad1843_gain_RECLEV = {
+       .negative = 0,
+       .lfield   = &ad1843_LIG,
+       .rfield   = &ad1843_RIG
+};
+static const struct ad1843_gain ad1843_gain_LINE = {
+       .negative = 1,
+       .lfield   = &ad1843_LX1M,
+       .rfield   = &ad1843_RX1M,
+       .lmute    = &ad1843_LX1MM,
+       .rmute    = &ad1843_RX1MM
+};
+static const struct ad1843_gain ad1843_gain_LINE_2 = {
+       .negative = 1,
+       .lfield   = &ad1843_LDA2G,
+       .rfield   = &ad1843_RDA2G,
+       .lmute    = &ad1843_LDA2GM,
+       .rmute    = &ad1843_RDA2GM
+};
+static const struct ad1843_gain ad1843_gain_MIC = {
+       .negative = 1,
+       .lfield   = &ad1843_LMCM,
+       .rfield   = &ad1843_RMCM,
+       .lmute    = &ad1843_LMCMM,
+       .rmute    = &ad1843_RMCMM
+};
+static const struct ad1843_gain ad1843_gain_PCM_0 = {
+       .negative = 1,
+       .lfield   = &ad1843_LDA1G,
+       .rfield   = &ad1843_RDA1G,
+       .lmute    = &ad1843_LDA1GM,
+       .rmute    = &ad1843_RDA1GM
+};
+static const struct ad1843_gain ad1843_gain_PCM_1 = {
+       .negative = 1,
+       .lfield   = &ad1843_LD2M,
+       .rfield   = &ad1843_RD2M,
+       .lmute    = &ad1843_LD2MM,
+       .rmute    = &ad1843_RD2MM
+};
+
+static const struct ad1843_gain *ad1843_gain[AD1843_GAIN_SIZE] =
+{
+       &ad1843_gain_RECLEV,
+       &ad1843_gain_LINE,
+       &ad1843_gain_LINE_2,
+       &ad1843_gain_MIC,
+       &ad1843_gain_PCM_0,
+       &ad1843_gain_PCM_1,
+};
+
+/* read the current value of an AD1843 bitfield. */
+
+static int ad1843_read_bits(struct snd_ad1843 *ad1843,
+                           const struct ad1843_bitfield *field)
+{
+       int w;
+
+       w = ad1843->read(ad1843->chip, field->reg);
+       return w >> field->lo_bit & ((1 << field->nbits) - 1);
+}
+
+/*
+ * write a new value to an AD1843 bitfield and return the old value.
+ */
+
+static int ad1843_write_bits(struct snd_ad1843 *ad1843,
+                            const struct ad1843_bitfield *field,
+                            int newval)
+{
+       int w, mask, oldval, newbits;
+
+       w = ad1843->read(ad1843->chip, field->reg);
+       mask = ((1 << field->nbits) - 1) << field->lo_bit;
+       oldval = (w & mask) >> field->lo_bit;
+       newbits = (newval << field->lo_bit) & mask;
+       w = (w & ~mask) | newbits;
+       ad1843->write(ad1843->chip, field->reg, w);
+
+       return oldval;
+}
+
+/*
+ * ad1843_read_multi reads multiple bitfields from the same AD1843
+ * register.  It uses a single read cycle to do it.  (Reading the
+ * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20
+ * microseconds.)
+ *
+ * Called like this.
+ *
+ *  ad1843_read_multi(ad1843, nfields,
+ *                   &ad1843_FIELD1, &val1,
+ *                   &ad1843_FIELD2, &val2, ...);
+ */
+
+static void ad1843_read_multi(struct snd_ad1843 *ad1843, int argcount, ...)
+{
+       va_list ap;
+       const struct ad1843_bitfield *fp;
+       int w = 0, mask, *value, reg = -1;
+
+       va_start(ap, argcount);
+       while (--argcount >= 0) {
+               fp = va_arg(ap, const struct ad1843_bitfield *);
+               value = va_arg(ap, int *);
+               if (reg == -1) {
+                       reg = fp->reg;
+                       w = ad1843->read(ad1843->chip, reg);
+               }
+
+               mask = (1 << fp->nbits) - 1;
+               *value = w >> fp->lo_bit & mask;
+       }
+       va_end(ap);
+}
+
+/*
+ * ad1843_write_multi stores multiple bitfields into the same AD1843
+ * register.  It uses one read and one write cycle to do it.
+ *
+ * Called like this.
+ *
+ *  ad1843_write_multi(ad1843, nfields,
+ *                    &ad1843_FIELD1, val1,
+ *                    &ad1843_FIELF2, val2, ...);
+ */
+
+static void ad1843_write_multi(struct snd_ad1843 *ad1843, int argcount, ...)
+{
+       va_list ap;
+       int reg;
+       const struct ad1843_bitfield *fp;
+       int value;
+       int w, m, mask, bits;
+
+       mask = 0;
+       bits = 0;
+       reg = -1;
+
+       va_start(ap, argcount);
+       while (--argcount >= 0) {
+               fp = va_arg(ap, const struct ad1843_bitfield *);
+               value = va_arg(ap, int);
+               if (reg == -1)
+                       reg = fp->reg;
+               else
+                       BUG_ON(reg != fp->reg);
+               m = ((1 << fp->nbits) - 1) << fp->lo_bit;
+               mask |= m;
+               bits |= (value << fp->lo_bit) & m;
+       }
+       va_end(ap);
+
+       if (~mask & 0xFFFF)
+               w = ad1843->read(ad1843->chip, reg);
+       else
+               w = 0;
+       w = (w & ~mask) | bits;
+       ad1843->write(ad1843->chip, reg, w);
+}
+
+int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id)
+{
+       const struct ad1843_gain *gp = ad1843_gain[id];
+       int ret;
+
+       ret = (1 << gp->lfield->nbits);
+       if (!gp->lmute)
+               ret -= 1;
+       return ret;
+}
+
+/*
+ * ad1843_get_gain reads the specified register and extracts the gain value
+ * using the supplied gain type.
+ */
+
+int ad1843_get_gain(struct snd_ad1843 *ad1843, int id)
+{
+       int lg, rg, lm, rm;
+       const struct ad1843_gain *gp = ad1843_gain[id];
+       unsigned short mask = (1 << gp->lfield->nbits) - 1;
+
+       ad1843_read_multi(ad1843, 2, gp->lfield, &lg, gp->rfield, &rg);
+       if (gp->negative) {
+               lg = mask - lg;
+               rg = mask - rg;
+       }
+       if (gp->lmute) {
+               ad1843_read_multi(ad1843, 2, gp->lmute, &lm, gp->rmute, &rm);
+               if (lm)
+                       lg = 0;
+               if (rm)
+                       rg = 0;
+       }
+       return lg << 0 | rg << 8;
+}
+
+/*
+ * Set an audio channel's gain.
+ *
+ * Returns the new gain, which may be lower than the old gain.
+ */
+
+int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval)
+{
+       const struct ad1843_gain *gp = ad1843_gain[id];
+       unsigned short mask = (1 << gp->lfield->nbits) - 1;
+
+       int lg = (newval >> 0) & mask;
+       int rg = (newval >> 8) & mask;
+       int lm = (lg == 0) ? 1 : 0;
+       int rm = (rg == 0) ? 1 : 0;
+
+       if (gp->negative) {
+               lg = mask - lg;
+               rg = mask - rg;
+       }
+       if (gp->lmute)
+               ad1843_write_multi(ad1843, 2, gp->lmute, lm, gp->rmute, rm);
+       ad1843_write_multi(ad1843, 2, gp->lfield, lg, gp->rfield, rg);
+       return ad1843_get_gain(ad1843, id);
+}
+
+/* Returns the current recording source */
+
+int ad1843_get_recsrc(struct snd_ad1843 *ad1843)
+{
+       int val = ad1843_read_bits(ad1843, &ad1843_LSS);
+
+       if (val < 0 || val > 2) {
+               val = 2;
+               ad1843_write_multi(ad1843, 2,
+                                  &ad1843_LSS, val, &ad1843_RSS, val);
+       }
+       return val;
+}
+
+/*
+ * Set recording source.
+ *
+ * Returns newsrc on success, -errno on failure.
+ */
+
+int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc)
+{
+       if (newsrc < 0 || newsrc > 2)
+               return -EINVAL;
+
+       ad1843_write_multi(ad1843, 2, &ad1843_LSS, newsrc, &ad1843_RSS, newsrc);
+       return newsrc;
+}
+
+/* Setup ad1843 for D/A conversion. */
+
+void ad1843_setup_dac(struct snd_ad1843 *ad1843,
+                     unsigned int id,
+                     unsigned int framerate,
+                     snd_pcm_format_t fmt,
+                     unsigned int channels)
+{
+       int ad_fmt = 0, ad_mode = 0;
+
+       switch (fmt) {
+       case SNDRV_PCM_FORMAT_S8:
+               ad_fmt = 0;
+               break;
+       case SNDRV_PCM_FORMAT_U8:
+               ad_fmt = 0;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               ad_fmt = 1;
+               break;
+       case SNDRV_PCM_FORMAT_MU_LAW:
+               ad_fmt = 2;
+               break;
+       case SNDRV_PCM_FORMAT_A_LAW:
+               ad_fmt = 3;
+               break;
+       default:
+               break;
+       }
+
+       switch (channels) {
+       case 2:
+               ad_mode = 0;
+               break;
+       case 1:
+               ad_mode = 1;
+               break;
+       default:
+               break;
+       }
+
+       if (id) {
+               ad1843_write_bits(ad1843, &ad1843_C2C, framerate);
+               ad1843_write_multi(ad1843, 2,
+                                  &ad1843_DA2SM, ad_mode,
+                                  &ad1843_DA2F, ad_fmt);
+       } else {
+               ad1843_write_bits(ad1843, &ad1843_C1C, framerate);
+               ad1843_write_multi(ad1843, 2,
+                                  &ad1843_DA1SM, ad_mode,
+                                  &ad1843_DA1F, ad_fmt);
+       }
+}
+
+void ad1843_shutdown_dac(struct snd_ad1843 *ad1843, unsigned int id)
+{
+       if (id)
+               ad1843_write_bits(ad1843, &ad1843_DA2F, 1);
+       else
+               ad1843_write_bits(ad1843, &ad1843_DA1F, 1);
+}
+
+void ad1843_setup_adc(struct snd_ad1843 *ad1843,
+                     unsigned int framerate,
+                     snd_pcm_format_t fmt,
+                     unsigned int channels)
+{
+       int da_fmt = 0;
+
+       switch (fmt) {
+       case SNDRV_PCM_FORMAT_S8:       da_fmt = 0; break;
+       case SNDRV_PCM_FORMAT_U8:       da_fmt = 0; break;
+       case SNDRV_PCM_FORMAT_S16_LE:   da_fmt = 1; break;
+       case SNDRV_PCM_FORMAT_MU_LAW:   da_fmt = 2; break;
+       case SNDRV_PCM_FORMAT_A_LAW:    da_fmt = 3; break;
+       default:                break;
+       }
+
+       ad1843_write_bits(ad1843, &ad1843_C3C, framerate);
+       ad1843_write_multi(ad1843, 2,
+                          &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt);
+}
+
+void ad1843_shutdown_adc(struct snd_ad1843 *ad1843)
+{
+       /* nothing to do */
+}
+
+/*
+ * Fully initialize the ad1843.  As described in the AD1843 data
+ * sheet, section "START-UP SEQUENCE".  The numbered comments are
+ * subsection headings from the data sheet.  See the data sheet, pages
+ * 52-54, for more info.
+ *
+ * return 0 on success, -errno on failure.  */
+
+int ad1843_init(struct snd_ad1843 *ad1843)
+{
+       unsigned long later;
+
+       if (ad1843_read_bits(ad1843, &ad1843_INIT) != 0) {
+               printk(KERN_ERR "ad1843: AD1843 won't initialize\n");
+               return -EIO;
+       }
+
+       ad1843_write_bits(ad1843, &ad1843_SCF, 1);
+
+       /* 4. Put the conversion resources into standby. */
+       ad1843_write_bits(ad1843, &ad1843_PDNI, 0);
+       later = jiffies + msecs_to_jiffies(500);
+
+       while (ad1843_read_bits(ad1843, &ad1843_PDNO)) {
+               if (time_after(jiffies, later)) {
+                       printk(KERN_ERR
+                              "ad1843: AD1843 won't power up\n");
+                       return -EIO;
+               }
+               schedule_timeout_interruptible(5);
+       }
+
+       /* 5. Power up the clock generators and enable clock output pins. */
+       ad1843_write_multi(ad1843, 3,
+                          &ad1843_C1EN, 1,
+                          &ad1843_C2EN, 1,
+                          &ad1843_C3EN, 1);
+
+       /* 6. Configure conversion resources while they are in standby. */
+
+       /* DAC1/2 use clock 1/2 as source, ADC uses clock 3.  Always. */
+       ad1843_write_multi(ad1843, 4,
+                          &ad1843_DA1C, 1,
+                          &ad1843_DA2C, 2,
+                          &ad1843_ADLC, 3,
+                          &ad1843_ADRC, 3);
+
+       /* 7. Enable conversion resources. */
+       ad1843_write_bits(ad1843, &ad1843_ADTLK, 1);
+       ad1843_write_multi(ad1843, 7,
+                          &ad1843_ANAEN, 1,
+                          &ad1843_AAMEN, 1,
+                          &ad1843_DA1EN, 1,
+                          &ad1843_DA2EN, 1,
+                          &ad1843_DDMEN, 1,
+                          &ad1843_ADLEN, 1,
+                          &ad1843_ADREN, 1);
+
+       /* 8. Configure conversion resources while they are enabled. */
+
+       /* set gain to 0 for all channels */
+       ad1843_set_gain(ad1843, AD1843_GAIN_RECLEV, 0);
+       ad1843_set_gain(ad1843, AD1843_GAIN_LINE, 0);
+       ad1843_set_gain(ad1843, AD1843_GAIN_LINE_2, 0);
+       ad1843_set_gain(ad1843, AD1843_GAIN_MIC, 0);
+       ad1843_set_gain(ad1843, AD1843_GAIN_PCM_0, 0);
+       ad1843_set_gain(ad1843, AD1843_GAIN_PCM_1, 0);
+
+       /* Unmute all channels. */
+       /* DAC1 */
+       ad1843_write_multi(ad1843, 2, &ad1843_LDA1GM, 0, &ad1843_RDA1GM, 0);
+       /* DAC2 */
+       ad1843_write_multi(ad1843, 2, &ad1843_LDA2GM, 0, &ad1843_RDA2GM, 0);
+
+       /* Set default recording source to Line In and set
+        * mic gain to +20 dB.
+        */
+       ad1843_set_recsrc(ad1843, 2);
+       ad1843_write_multi(ad1843, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1);
+
+       /* Set Speaker Out level to +/- 4V and unmute it. */
+       ad1843_write_multi(ad1843, 3,
+                          &ad1843_HPOS, 1,
+                          &ad1843_HPOM, 0,
+                          &ad1843_MPOM, 0);
+
+       return 0;
+}
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c
new file mode 100644 (file)
index 0000000..db495be
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ *  Driver for A2 audio system used in SGI machines
+ *  Copyright (c) 2008 Thomas Bogendoerfer <tsbogend@alpha.fanken.de>
+ *
+ *  Based on OSS code from Ladislav Michl <ladis@linux-mips.org>, which
+ *  was based on code from Ulf Carlsson
+ *
+ *  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.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm-indirect.h>
+#include <sound/initval.h>
+
+#include "hal2.h"
+
+static int index = SNDRV_DEFAULT_IDX1;  /* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1;   /* ID for this card */
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for SGI HAL2 soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for SGI HAL2 soundcard.");
+MODULE_DESCRIPTION("ALSA driver for SGI HAL2 audio");
+MODULE_AUTHOR("Thomas Bogendoerfer");
+MODULE_LICENSE("GPL");
+
+
+#define H2_BLOCK_SIZE  1024
+#define H2_BUF_SIZE    16384
+
+struct hal2_pbus {
+       struct hpc3_pbus_dmacregs *pbus;
+       int pbusnr;
+       unsigned int ctrl;              /* Current state of pbus->pbdma_ctrl */
+};
+
+struct hal2_desc {
+       struct hpc_dma_desc desc;
+       u32 pad;                        /* padding */
+};
+
+struct hal2_codec {
+       struct snd_pcm_indirect pcm_indirect;
+       struct snd_pcm_substream *substream;
+
+       unsigned char *buffer;
+       dma_addr_t buffer_dma;
+       struct hal2_desc *desc;
+       dma_addr_t desc_dma;
+       int desc_count;
+       struct hal2_pbus pbus;
+       int voices;                     /* mono/stereo */
+       unsigned int sample_rate;
+       unsigned int master;            /* Master frequency */
+       unsigned short mod;             /* MOD value */
+       unsigned short inc;             /* INC value */
+};
+
+#define H2_MIX_OUTPUT_ATT      0
+#define H2_MIX_INPUT_GAIN      1
+
+struct snd_hal2 {
+       struct snd_card *card;
+
+       struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */
+       struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */
+       struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */
+       struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */
+
+       struct hal2_codec dac;
+       struct hal2_codec adc;
+};
+
+#define H2_INDIRECT_WAIT(regs) while (hal2_read(&regs->isr) & H2_ISR_TSTATUS);
+
+#define H2_READ_ADDR(addr)     (addr | (1<<7))
+#define H2_WRITE_ADDR(addr)    (addr)
+
+static inline u32 hal2_read(u32 *reg)
+{
+       return __raw_readl(reg);
+}
+
+static inline void hal2_write(u32 val, u32 *reg)
+{
+       __raw_writel(val, reg);
+}
+
+
+static u32 hal2_i_read32(struct snd_hal2 *hal2, u16 addr)
+{
+       u32 ret;
+       struct hal2_ctl_regs *regs = hal2->ctl_regs;
+
+       hal2_write(H2_READ_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+       ret = hal2_read(&regs->idr0) & 0xffff;
+       hal2_write(H2_READ_ADDR(addr) | 0x1, &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+       ret |= (hal2_read(&regs->idr0) & 0xffff) << 16;
+       return ret;
+}
+
+static void hal2_i_write16(struct snd_hal2 *hal2, u16 addr, u16 val)
+{
+       struct hal2_ctl_regs *regs = hal2->ctl_regs;
+
+       hal2_write(val, &regs->idr0);
+       hal2_write(0, &regs->idr1);
+       hal2_write(0, &regs->idr2);
+       hal2_write(0, &regs->idr3);
+       hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_write32(struct snd_hal2 *hal2, u16 addr, u32 val)
+{
+       struct hal2_ctl_regs *regs = hal2->ctl_regs;
+
+       hal2_write(val & 0xffff, &regs->idr0);
+       hal2_write(val >> 16, &regs->idr1);
+       hal2_write(0, &regs->idr2);
+       hal2_write(0, &regs->idr3);
+       hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_setbit16(struct snd_hal2 *hal2, u16 addr, u16 bit)
+{
+       struct hal2_ctl_regs *regs = hal2->ctl_regs;
+
+       hal2_write(H2_READ_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+       hal2_write((hal2_read(&regs->idr0) & 0xffff) | bit, &regs->idr0);
+       hal2_write(0, &regs->idr1);
+       hal2_write(0, &regs->idr2);
+       hal2_write(0, &regs->idr3);
+       hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_clearbit16(struct snd_hal2 *hal2, u16 addr, u16 bit)
+{
+       struct hal2_ctl_regs *regs = hal2->ctl_regs;
+
+       hal2_write(H2_READ_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+       hal2_write((hal2_read(&regs->idr0) & 0xffff) & ~bit, &regs->idr0);
+       hal2_write(0, &regs->idr1);
+       hal2_write(0, &regs->idr2);
+       hal2_write(0, &regs->idr3);
+       hal2_write(H2_WRITE_ADDR(addr), &regs->iar);
+       H2_INDIRECT_WAIT(regs);
+}
+
+static int hal2_gain_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       switch ((int)kcontrol->private_value) {
+       case H2_MIX_OUTPUT_ATT:
+               uinfo->value.integer.max = 31;
+               break;
+       case H2_MIX_INPUT_GAIN:
+               uinfo->value.integer.max = 15;
+               break;
+       }
+       return 0;
+}
+
+static int hal2_gain_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol);
+       u32 tmp;
+       int l, r;
+
+       switch ((int)kcontrol->private_value) {
+       case H2_MIX_OUTPUT_ATT:
+               tmp = hal2_i_read32(hal2, H2I_DAC_C2);
+               if (tmp & H2I_C2_MUTE) {
+                       l = 0;
+                       r = 0;
+               } else {
+                       l = 31 - ((tmp >> H2I_C2_L_ATT_SHIFT) & 31);
+                       r = 31 - ((tmp >> H2I_C2_R_ATT_SHIFT) & 31);
+               }
+               break;
+       case H2_MIX_INPUT_GAIN:
+               tmp = hal2_i_read32(hal2, H2I_ADC_C2);
+               l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15;
+               r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15;
+               break;
+       }
+       ucontrol->value.integer.value[0] = l;
+       ucontrol->value.integer.value[1] = r;
+
+       return 0;
+}
+
+static int hal2_gain_put(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol);
+       u32 old, new;
+       int l, r;
+
+       l = ucontrol->value.integer.value[0];
+       r = ucontrol->value.integer.value[1];
+
+       switch ((int)kcontrol->private_value) {
+       case H2_MIX_OUTPUT_ATT:
+               old = hal2_i_read32(hal2, H2I_DAC_C2);
+               new = old & ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
+               if (l | r) {
+                       l = 31 - l;
+                       r = 31 - r;
+                       new |= (l << H2I_C2_L_ATT_SHIFT);
+                       new |= (r << H2I_C2_R_ATT_SHIFT);
+               } else
+                       new |= H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE;
+               hal2_i_write32(hal2, H2I_DAC_C2, new);
+               break;
+       case H2_MIX_INPUT_GAIN:
+               old = hal2_i_read32(hal2, H2I_ADC_C2);
+               new = old & ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M);
+               new |= (l << H2I_C2_L_GAIN_SHIFT);
+               new |= (r << H2I_C2_R_GAIN_SHIFT);
+               hal2_i_write32(hal2, H2I_ADC_C2, new);
+               break;
+       }
+       return old != new;
+}
+
+static struct snd_kcontrol_new hal2_ctrl_headphone __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Headphone Playback Volume",
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = H2_MIX_OUTPUT_ATT,
+       .info           = hal2_gain_info,
+       .get            = hal2_gain_get,
+       .put            = hal2_gain_put,
+};
+
+static struct snd_kcontrol_new hal2_ctrl_mic __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Mic Capture Volume",
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = H2_MIX_INPUT_GAIN,
+       .info           = hal2_gain_info,
+       .get            = hal2_gain_get,
+       .put            = hal2_gain_put,
+};
+
+static int __devinit hal2_mixer_create(struct snd_hal2 *hal2)
+{
+       int err;
+
+       /* mute DAC */
+       hal2_i_write32(hal2, H2I_DAC_C2,
+                      H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
+       /* mute ADC */
+       hal2_i_write32(hal2, H2I_ADC_C2, 0);
+
+       err = snd_ctl_add(hal2->card,
+                         snd_ctl_new1(&hal2_ctrl_headphone, hal2));
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(hal2->card,
+                         snd_ctl_new1(&hal2_ctrl_mic, hal2));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static irqreturn_t hal2_interrupt(int irq, void *dev_id)
+{
+       struct snd_hal2 *hal2 = dev_id;
+       irqreturn_t ret = IRQ_NONE;
+
+       /* decide what caused this interrupt */
+       if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
+               snd_pcm_period_elapsed(hal2->dac.substream);
+               ret = IRQ_HANDLED;
+       }
+       if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) {
+               snd_pcm_period_elapsed(hal2->adc.substream);
+               ret = IRQ_HANDLED;
+       }
+       return ret;
+}
+
+static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate)
+{
+       unsigned short mod;
+
+       if (44100 % rate < 48000 % rate) {
+               mod = 4 * 44100 / rate;
+               codec->master = 44100;
+       } else {
+               mod = 4 * 48000 / rate;
+               codec->master = 48000;
+       }
+
+       codec->inc = 4;
+       codec->mod = mod;
+       rate = 4 * codec->master / mod;
+
+       return rate;
+}
+
+static void hal2_set_dac_rate(struct snd_hal2 *hal2)
+{
+       unsigned int master = hal2->dac.master;
+       int inc = hal2->dac.inc;
+       int mod = hal2->dac.mod;
+
+       hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0);
+       hal2_i_write32(hal2, H2I_BRES1_C2,
+                      ((0xffff & (inc - mod - 1)) << 16) | inc);
+}
+
+static void hal2_set_adc_rate(struct snd_hal2 *hal2)
+{
+       unsigned int master = hal2->adc.master;
+       int inc = hal2->adc.inc;
+       int mod = hal2->adc.mod;
+
+       hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0);
+       hal2_i_write32(hal2, H2I_BRES2_C2,
+                      ((0xffff & (inc - mod - 1)) << 16) | inc);
+}
+
+static void hal2_setup_dac(struct snd_hal2 *hal2)
+{
+       unsigned int fifobeg, fifoend, highwater, sample_size;
+       struct hal2_pbus *pbus = &hal2->dac.pbus;
+
+       /* Now we set up some PBUS information. The PBUS needs information about
+        * what portion of the fifo it will use. If it's receiving or
+        * transmitting, and finally whether the stream is little endian or big
+        * endian. The information is written later, on the start call.
+        */
+       sample_size = 2 * hal2->dac.voices;
+       /* Fifo should be set to hold exactly four samples. Highwater mark
+        * should be set to two samples. */
+       highwater = (sample_size * 2) >> 1;     /* halfwords */
+       fifobeg = 0;                            /* playback is first */
+       fifoend = (sample_size * 4) >> 3;       /* doublewords */
+       pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD |
+                    (highwater << 8) | (fifobeg << 16) | (fifoend << 24);
+       /* We disable everything before we do anything at all */
+       pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+       hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
+       /* Setup the HAL2 for playback */
+       hal2_set_dac_rate(hal2);
+       /* Set endianess */
+       hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
+       /* Set DMA bus */
+       hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
+       /* We are using 1st Bresenham clock generator for playback */
+       hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
+                       | (1 << H2I_C1_CLKID_SHIFT)
+                       | (hal2->dac.voices << H2I_C1_DATAT_SHIFT));
+}
+
+static void hal2_setup_adc(struct snd_hal2 *hal2)
+{
+       unsigned int fifobeg, fifoend, highwater, sample_size;
+       struct hal2_pbus *pbus = &hal2->adc.pbus;
+
+       sample_size = 2 * hal2->adc.voices;
+       highwater = (sample_size * 2) >> 1;             /* halfwords */
+       fifobeg = (4 * 4) >> 3;                         /* record is second */
+       fifoend = (4 * 4 + sample_size * 4) >> 3;       /* doublewords */
+       pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD |
+                    (highwater << 8) | (fifobeg << 16) | (fifoend << 24);
+       pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+       hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
+       /* Setup the HAL2 for record */
+       hal2_set_adc_rate(hal2);
+       /* Set endianess */
+       hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
+       /* Set DMA bus */
+       hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
+       /* We are using 2nd Bresenham clock generator for record */
+       hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
+                       | (2 << H2I_C1_CLKID_SHIFT)
+                       | (hal2->adc.voices << H2I_C1_DATAT_SHIFT));
+}
+
+static void hal2_start_dac(struct snd_hal2 *hal2)
+{
+       struct hal2_pbus *pbus = &hal2->dac.pbus;
+
+       pbus->pbus->pbdma_dptr = hal2->dac.desc_dma;
+       pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
+       /* enable DAC */
+       hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
+}
+
+static void hal2_start_adc(struct snd_hal2 *hal2)
+{
+       struct hal2_pbus *pbus = &hal2->adc.pbus;
+
+       pbus->pbus->pbdma_dptr = hal2->adc.desc_dma;
+       pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
+       /* enable ADC */
+       hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
+}
+
+static inline void hal2_stop_dac(struct snd_hal2 *hal2)
+{
+       hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+       /* The HAL2 itself may remain enabled safely */
+}
+
+static inline void hal2_stop_adc(struct snd_hal2 *hal2)
+{
+       hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+}
+
+static int hal2_alloc_dmabuf(struct hal2_codec *codec)
+{
+       struct hal2_desc *desc;
+       dma_addr_t desc_dma, buffer_dma;
+       int count = H2_BUF_SIZE / H2_BLOCK_SIZE;
+       int i;
+
+       codec->buffer = dma_alloc_noncoherent(NULL, H2_BUF_SIZE,
+                                             &buffer_dma, GFP_KERNEL);
+       if (!codec->buffer)
+               return -ENOMEM;
+       desc = dma_alloc_noncoherent(NULL, count * sizeof(struct hal2_desc),
+                                    &desc_dma, GFP_KERNEL);
+       if (!desc) {
+               dma_free_noncoherent(NULL, H2_BUF_SIZE,
+                                    codec->buffer, buffer_dma);
+               return -ENOMEM;
+       }
+       codec->buffer_dma = buffer_dma;
+       codec->desc_dma = desc_dma;
+       codec->desc = desc;
+       for (i = 0; i < count; i++) {
+               desc->desc.pbuf = buffer_dma + i * H2_BLOCK_SIZE;
+               desc->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE;
+               desc->desc.pnext = (i == count - 1) ?
+                     desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc);
+               desc++;
+       }
+       dma_cache_sync(NULL, codec->desc, count * sizeof(struct hal2_desc),
+                      DMA_TO_DEVICE);
+       codec->desc_count = count;
+       return 0;
+}
+
+static void hal2_free_dmabuf(struct hal2_codec *codec)
+{
+       dma_free_noncoherent(NULL, codec->desc_count * sizeof(struct hal2_desc),
+                            codec->desc, codec->desc_dma);
+       dma_free_noncoherent(NULL, H2_BUF_SIZE, codec->buffer,
+                            codec->buffer_dma);
+}
+
+static struct snd_pcm_hardware hal2_pcm_hw = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_BLOCK_TRANSFER),
+       .formats =          SNDRV_PCM_FMTBIT_S16_BE,
+       .rates =            SNDRV_PCM_RATE_8000_48000,
+       .rate_min =         8000,
+       .rate_max =         48000,
+       .channels_min =     2,
+       .channels_max =     2,
+       .buffer_bytes_max = 65536,
+       .period_bytes_min = 1024,
+       .period_bytes_max = 65536,
+       .periods_min =      2,
+       .periods_max =      1024,
+};
+
+static int hal2_pcm_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       int err;
+
+       err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int hal2_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int hal2_playback_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       int err;
+
+       runtime->hw = hal2_pcm_hw;
+
+       err = hal2_alloc_dmabuf(&hal2->dac);
+       if (err)
+               return err;
+       return 0;
+}
+
+static int hal2_playback_close(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+
+       hal2_free_dmabuf(&hal2->dac);
+       return 0;
+}
+
+static int hal2_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hal2_codec *dac = &hal2->dac;
+
+       dac->voices = runtime->channels;
+       dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
+       memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
+       dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
+       dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
+       dac->substream = substream;
+       hal2_setup_dac(hal2);
+       return 0;
+}
+
+static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma;
+               hal2->dac.pcm_indirect.hw_data = 0;
+               substream->ops->ack(substream);
+               hal2_start_dac(hal2);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               hal2_stop_dac(hal2);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static snd_pcm_uframes_t
+hal2_playback_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct hal2_codec *dac = &hal2->dac;
+
+       return snd_pcm_indirect_playback_pointer(substream, &dac->pcm_indirect,
+                                                dac->pbus.pbus->pbdma_bptr);
+}
+
+static void hal2_playback_transfer(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_indirect *rec, size_t bytes)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       unsigned char *buf = hal2->dac.buffer + rec->hw_data;
+
+       memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes);
+       dma_cache_sync(NULL, buf, bytes, DMA_TO_DEVICE);
+
+}
+
+static int hal2_playback_ack(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct hal2_codec *dac = &hal2->dac;
+
+       dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
+       snd_pcm_indirect_playback_transfer(substream,
+                                          &dac->pcm_indirect,
+                                          hal2_playback_transfer);
+       return 0;
+}
+
+static int hal2_capture_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct hal2_codec *adc = &hal2->adc;
+       int err;
+
+       runtime->hw = hal2_pcm_hw;
+
+       err = hal2_alloc_dmabuf(adc);
+       if (err)
+               return err;
+       return 0;
+}
+
+static int hal2_capture_close(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+
+       hal2_free_dmabuf(&hal2->adc);
+       return 0;
+}
+
+static int hal2_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hal2_codec *adc = &hal2->adc;
+
+       adc->voices = runtime->channels;
+       adc->sample_rate = hal2_compute_rate(adc, runtime->rate);
+       memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
+       adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
+       adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
+       adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
+       adc->substream = substream;
+       hal2_setup_adc(hal2);
+       return 0;
+}
+
+static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma;
+               hal2->adc.pcm_indirect.hw_data = 0;
+               printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma);
+               hal2_start_adc(hal2);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               hal2_stop_adc(hal2);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static snd_pcm_uframes_t
+hal2_capture_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct hal2_codec *adc = &hal2->adc;
+
+       return snd_pcm_indirect_capture_pointer(substream, &adc->pcm_indirect,
+                                               adc->pbus.pbus->pbdma_bptr);
+}
+
+static void hal2_capture_transfer(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_indirect *rec, size_t bytes)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       unsigned char *buf = hal2->adc.buffer + rec->hw_data;
+
+       dma_cache_sync(NULL, buf, bytes, DMA_FROM_DEVICE);
+       memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes);
+}
+
+static int hal2_capture_ack(struct snd_pcm_substream *substream)
+{
+       struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
+       struct hal2_codec *adc = &hal2->adc;
+
+       snd_pcm_indirect_capture_transfer(substream,
+                                         &adc->pcm_indirect,
+                                         hal2_capture_transfer);
+       return 0;
+}
+
+static struct snd_pcm_ops hal2_playback_ops = {
+       .open =        hal2_playback_open,
+       .close =       hal2_playback_close,
+       .ioctl =       snd_pcm_lib_ioctl,
+       .hw_params =   hal2_pcm_hw_params,
+       .hw_free =     hal2_pcm_hw_free,
+       .prepare =     hal2_playback_prepare,
+       .trigger =     hal2_playback_trigger,
+       .pointer =     hal2_playback_pointer,
+       .ack =         hal2_playback_ack,
+};
+
+static struct snd_pcm_ops hal2_capture_ops = {
+       .open =        hal2_capture_open,
+       .close =       hal2_capture_close,
+       .ioctl =       snd_pcm_lib_ioctl,
+       .hw_params =   hal2_pcm_hw_params,
+       .hw_free =     hal2_pcm_hw_free,
+       .prepare =     hal2_capture_prepare,
+       .trigger =     hal2_capture_trigger,
+       .pointer =     hal2_capture_pointer,
+       .ack =         hal2_capture_ack,
+};
+
+static int __devinit hal2_pcm_create(struct snd_hal2 *hal2)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       /* create first pcm device with one outputs and one input */
+       err = snd_pcm_new(hal2->card, "SGI HAL2 Audio", 0, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       pcm->private_data = hal2;
+       strcpy(pcm->name, "SGI HAL2");
+
+       /* set operators */
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &hal2_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &hal2_capture_ops);
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                                          snd_dma_continuous_data(GFP_KERNEL),
+                                          0, 1024 * 1024);
+
+       return 0;
+}
+
+static int hal2_dev_free(struct snd_device *device)
+{
+       struct snd_hal2 *hal2 = device->device_data;
+
+       free_irq(SGI_HPCDMA_IRQ, hal2);
+       kfree(hal2);
+       return 0;
+}
+
+static struct snd_device_ops hal2_ops = {
+       .dev_free = hal2_dev_free,
+};
+
+static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3,
+                           int index)
+{
+       codec->pbus.pbusnr = index;
+       codec->pbus.pbus = &hpc3->pbdma[index];
+}
+
+static int hal2_detect(struct snd_hal2 *hal2)
+{
+       unsigned short board, major, minor;
+       unsigned short rev;
+
+       /* reset HAL2 */
+       hal2_write(0, &hal2->ctl_regs->isr);
+
+       /* release reset */
+       hal2_write(H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N,
+                  &hal2->ctl_regs->isr);
+
+
+       hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE);
+       rev = hal2_read(&hal2->ctl_regs->rev);
+       if (rev & H2_REV_AUDIO_PRESENT)
+               return -ENODEV;
+
+       board = (rev & H2_REV_BOARD_M) >> 12;
+       major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;
+       minor = (rev & H2_REV_MINOR_CHIP_M);
+
+       printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n",
+              board, major, minor);
+
+       return 0;
+}
+
+static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip)
+{
+       struct snd_hal2 *hal2;
+       struct hpc3_regs *hpc3 = hpc3c0;
+       int err;
+
+       hal2 = kzalloc(sizeof(struct snd_hal2), GFP_KERNEL);
+       if (!hal2)
+               return -ENOMEM;
+
+       hal2->card = card;
+
+       if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED,
+                       "SGI HAL2", hal2)) {
+               printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ);
+               kfree(hal2);
+               return -EAGAIN;
+       }
+
+       hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0];
+       hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1];
+       hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2];
+       hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3];
+
+       if (hal2_detect(hal2) < 0) {
+               kfree(hal2);
+               return -ENODEV;
+       }
+
+       hal2_init_codec(&hal2->dac, hpc3, 0);
+       hal2_init_codec(&hal2->adc, hpc3, 1);
+
+       /*
+        * All DMA channel interfaces in HAL2 are designed to operate with
+        * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles
+        * in D5. HAL2 is a 16-bit device which can accept both big and little
+        * endian format. It assumes that even address bytes are on high
+        * portion of PBUS (15:8) and assumes that HPC3 is programmed to
+        * accept a live (unsynchronized) version of P_DREQ_N from HAL2.
+        */
+#define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \
+                         (2 << HPC3_DMACFG_D4R_SHIFT) | \
+                         (2 << HPC3_DMACFG_D5R_SHIFT) | \
+                         (0 << HPC3_DMACFG_D3W_SHIFT) | \
+                         (2 << HPC3_DMACFG_D4W_SHIFT) | \
+                         (2 << HPC3_DMACFG_D5W_SHIFT) | \
+                               HPC3_DMACFG_DS16 | \
+                               HPC3_DMACFG_EVENHI | \
+                               HPC3_DMACFG_RTIME | \
+                         (8 << HPC3_DMACFG_BURST_SHIFT) | \
+                               HPC3_DMACFG_DRQLIVE)
+       /*
+        * Ignore what's mentioned in the specification and write value which
+        * works in The Real World (TM)
+        */
+       hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844;
+       hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844;
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, hal2, &hal2_ops);
+       if (err < 0) {
+               free_irq(SGI_HPCDMA_IRQ, hal2);
+               kfree(hal2);
+               return err;
+       }
+       *rchip = hal2;
+       return 0;
+}
+
+static int __devinit hal2_probe(struct platform_device *pdev)
+{
+       struct snd_card *card;
+       struct snd_hal2 *chip;
+       int err;
+
+       card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (card == NULL)
+               return -ENOMEM;
+
+       err = hal2_create(card, &chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       snd_card_set_dev(card, &pdev->dev);
+
+       err = hal2_pcm_create(chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       err = hal2_mixer_create(chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "SGI HAL2 Audio");
+       strcpy(card->shortname, "SGI HAL2 Audio");
+       sprintf(card->longname, "%s irq %i",
+               card->shortname,
+               SGI_HPCDMA_IRQ);
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       platform_set_drvdata(pdev, card);
+       return 0;
+}
+
+static int __exit hal2_remove(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+
+       snd_card_free(card);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver hal2_driver = {
+       .probe  = hal2_probe,
+       .remove = __devexit_p(hal2_remove),
+       .driver = {
+               .name   = "sgihal2",
+               .owner  = THIS_MODULE,
+       }
+};
+
+static int __init alsa_card_hal2_init(void)
+{
+       return platform_driver_register(&hal2_driver);
+}
+
+static void __exit alsa_card_hal2_exit(void)
+{
+       platform_driver_unregister(&hal2_driver);
+}
+
+module_init(alsa_card_hal2_init);
+module_exit(alsa_card_hal2_exit);
diff --git a/sound/mips/hal2.h b/sound/mips/hal2.h
new file mode 100644 (file)
index 0000000..f19828b
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef __HAL2_H
+#define __HAL2_H
+
+/*
+ *  Driver for HAL2 sound processors
+ *  Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se>
+ *  Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/types.h>
+
+/* Indirect status register */
+
+#define H2_ISR_TSTATUS         0x01    /* RO: transaction status 1=busy */
+#define H2_ISR_USTATUS         0x02    /* RO: utime status bit 1=armed */
+#define H2_ISR_QUAD_MODE       0x04    /* codec mode 0=indigo 1=quad */
+#define H2_ISR_GLOBAL_RESET_N  0x08    /* chip global reset 0=reset */
+#define H2_ISR_CODEC_RESET_N   0x10    /* codec/synth reset 0=reset  */
+
+/* Revision register */
+
+#define H2_REV_AUDIO_PRESENT   0x8000  /* RO: audio present 0=present */
+#define H2_REV_BOARD_M         0x7000  /* RO: bits 14:12, board revision */
+#define H2_REV_MAJOR_CHIP_M    0x00F0  /* RO: bits 7:4, major chip revision */
+#define H2_REV_MINOR_CHIP_M    0x000F  /* RO: bits 3:0, minor chip revision */
+
+/* Indirect address register */
+
+/*
+ * Address of indirect internal register to be accessed. A write to this
+ * register initiates read or write access to the indirect registers in the
+ * HAL2. Note that there af four indirect data registers for write access to
+ * registers larger than 16 byte.
+ */
+
+#define H2_IAR_TYPE_M          0xF000  /* bits 15:12, type of functional */
+                                       /* block the register resides in */
+                                       /* 1=DMA Port */
+                                       /* 9=Global DMA Control */
+                                       /* 2=Bresenham */
+                                       /* 3=Unix Timer */
+#define H2_IAR_NUM_M           0x0F00  /* bits 11:8 instance of the */
+                                       /* blockin which the indirect */
+                                       /* register resides */
+                                       /* If IAR_TYPE_M=DMA Port: */
+                                       /* 1=Synth In */
+                                       /* 2=AES In */
+                                       /* 3=AES Out */
+                                       /* 4=DAC Out */
+                                       /* 5=ADC Out */
+                                       /* 6=Synth Control */
+                                       /* If IAR_TYPE_M=Global DMA Control: */
+                                       /* 1=Control */
+                                       /* If IAR_TYPE_M=Bresenham: */
+                                       /* 1=Bresenham Clock Gen 1 */
+                                       /* 2=Bresenham Clock Gen 2 */
+                                       /* 3=Bresenham Clock Gen 3 */
+                                       /* If IAR_TYPE_M=Unix Timer: */
+                                       /* 1=Unix Timer */
+#define H2_IAR_ACCESS_SELECT   0x0080  /* 1=read 0=write */
+#define H2_IAR_PARAM           0x000C  /* Parameter Select */
+#define H2_IAR_RB_INDEX_M      0x0003  /* Read Back Index */
+                                       /* 00:word0 */
+                                       /* 01:word1 */
+                                       /* 10:word2 */
+                                       /* 11:word3 */
+/*
+ * HAL2 internal addressing
+ *
+ * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
+ * Indirect Data registers. Write the address to the Indirect Address register
+ * to transfer the data.
+ *
+ * We define the H2IR_* to the read address and H2IW_* to the write address and
+ * H2I_* to be fields in whatever register is referred to.
+ *
+ * When we write to indirect registers which are larger than one word (16 bit)
+ * we have to fill more than one indirect register before writing. When we read
+ * back however we have to read several times, each time with different Read
+ * Back Indexes (there are defs for doing this easily).
+ */
+
+/*
+ * Relay Control
+ */
+#define H2I_RELAY_C            0x9100
+#define H2I_RELAY_C_STATE      0x01            /* state of RELAY pin signal */
+
+/* DMA port enable */
+
+#define H2I_DMA_PORT_EN                0x9104
+#define H2I_DMA_PORT_EN_SY_IN  0x01            /* Synth_in DMA port */
+#define H2I_DMA_PORT_EN_AESRX  0x02            /* AES receiver DMA port */
+#define H2I_DMA_PORT_EN_AESTX  0x04            /* AES transmitter DMA port */
+#define H2I_DMA_PORT_EN_CODECTX        0x08            /* CODEC transmit DMA port */
+#define H2I_DMA_PORT_EN_CODECR 0x10            /* CODEC receive DMA port */
+
+#define H2I_DMA_END            0x9108          /* global dma endian select */
+#define H2I_DMA_END_SY_IN      0x01            /* Synth_in DMA port */
+#define H2I_DMA_END_AESRX      0x02            /* AES receiver DMA port */
+#define H2I_DMA_END_AESTX      0x04            /* AES transmitter DMA port */
+#define H2I_DMA_END_CODECTX    0x08            /* CODEC transmit DMA port */
+#define H2I_DMA_END_CODECR     0x10            /* CODEC receive DMA port */
+                                               /* 0=b_end 1=l_end */
+
+#define H2I_DMA_DRV            0x910C          /* global PBUS DMA enable */
+
+#define H2I_SYNTH_C            0x1104          /* Synth DMA control */
+
+#define H2I_AESRX_C            0x1204          /* AES RX dma control */
+
+#define H2I_C_TS_EN            0x20            /* Timestamp enable */
+#define H2I_C_TS_FRMT          0x40            /* Timestamp format */
+#define H2I_C_NAUDIO           0x80            /* Sign extend */
+
+/* AESRX CTL, 16 bit */
+
+#define H2I_AESTX_C            0x1304          /* AES TX DMA control */
+#define H2I_AESTX_C_CLKID_SHIFT        3               /* Bresenham Clock Gen 1-3 */
+#define H2I_AESTX_C_CLKID_M    0x18
+#define H2I_AESTX_C_DATAT_SHIFT        8               /* 1=mono 2=stereo (3=quad) */
+#define H2I_AESTX_C_DATAT_M    0x300
+
+/* CODEC registers */
+
+#define H2I_DAC_C1             0x1404          /* DAC DMA control, 16 bit */
+#define H2I_DAC_C2             0x1408          /* DAC DMA control, 32 bit */
+#define H2I_ADC_C1             0x1504          /* ADC DMA control, 16 bit */
+#define H2I_ADC_C2             0x1508          /* ADC DMA control, 32 bit */
+
+/* Bits in CTL1 register */
+
+#define H2I_C1_DMA_SHIFT       0               /* DMA channel */
+#define H2I_C1_DMA_M           0x7
+#define H2I_C1_CLKID_SHIFT     3               /* Bresenham Clock Gen 1-3 */
+#define H2I_C1_CLKID_M         0x18
+#define H2I_C1_DATAT_SHIFT     8               /* 1=mono 2=stereo (3=quad) */
+#define H2I_C1_DATAT_M         0x300
+
+/* Bits in CTL2 register */
+
+#define H2I_C2_R_GAIN_SHIFT    0               /* right a/d input gain */
+#define H2I_C2_R_GAIN_M                0xf
+#define H2I_C2_L_GAIN_SHIFT    4               /* left a/d input gain */
+#define H2I_C2_L_GAIN_M                0xf0
+#define H2I_C2_R_SEL           0x100           /* right input select */
+#define H2I_C2_L_SEL           0x200           /* left input select */
+#define H2I_C2_MUTE            0x400           /* mute */
+#define H2I_C2_DO1             0x00010000      /* digital output port bit 0 */
+#define H2I_C2_DO2             0x00020000      /* digital output port bit 1 */
+#define H2I_C2_R_ATT_SHIFT     18              /* right d/a output - */
+#define H2I_C2_R_ATT_M         0x007c0000      /* attenuation */
+#define H2I_C2_L_ATT_SHIFT     23              /* left d/a output - */
+#define H2I_C2_L_ATT_M         0x0f800000      /* attenuation */
+
+#define H2I_SYNTH_MAP_C                0x1104          /* synth dma handshake ctrl */
+
+/* Clock generator CTL 1, 16 bit */
+
+#define H2I_BRES1_C1           0x2104
+#define H2I_BRES2_C1           0x2204
+#define H2I_BRES3_C1           0x2304
+
+#define H2I_BRES_C1_SHIFT      0               /* 0=48.0 1=44.1 2=aes_rx */
+#define H2I_BRES_C1_M          0x03
+
+/* Clock generator CTL 2, 32 bit */
+
+#define H2I_BRES1_C2           0x2108
+#define H2I_BRES2_C2           0x2208
+#define H2I_BRES3_C2           0x2308
+
+#define H2I_BRES_C2_INC_SHIFT  0               /* increment value */
+#define H2I_BRES_C2_INC_M      0xffff
+#define H2I_BRES_C2_MOD_SHIFT  16              /* modcontrol value */
+#define H2I_BRES_C2_MOD_M      0xffff0000      /* modctrl=0xffff&(modinc-1) */
+
+/* Unix timer, 64 bit */
+
+#define H2I_UTIME              0x3104
+#define H2I_UTIME_0_LD         0xffff          /* microseconds, LSB's */
+#define H2I_UTIME_1_LD0                0x0f            /* microseconds, MSB's */
+#define H2I_UTIME_1_LD1                0xf0            /* tenths of microseconds */
+#define H2I_UTIME_2_LD         0xffff          /* seconds, LSB's */
+#define H2I_UTIME_3_LD         0xffff          /* seconds, MSB's */
+
+struct hal2_ctl_regs {
+       u32 _unused0[4];
+       u32 isr;                /* 0x10 Status Register */
+       u32 _unused1[3];
+       u32 rev;                /* 0x20 Revision Register */
+       u32 _unused2[3];
+       u32 iar;                /* 0x30 Indirect Address Register */
+       u32 _unused3[3];
+       u32 idr0;               /* 0x40 Indirect Data Register 0 */
+       u32 _unused4[3];
+       u32 idr1;               /* 0x50 Indirect Data Register 1 */
+       u32 _unused5[3];
+       u32 idr2;               /* 0x60 Indirect Data Register 2 */
+       u32 _unused6[3];
+       u32 idr3;               /* 0x70 Indirect Data Register 3 */
+};
+
+struct hal2_aes_regs {
+       u32 rx_stat[2]; /* Status registers */
+       u32 rx_cr[2];           /* Control registers */
+       u32 rx_ud[4];           /* User data window */
+       u32 rx_st[24];          /* Channel status data */
+
+       u32 tx_stat[1]; /* Status register */
+       u32 tx_cr[3];           /* Control registers */
+       u32 tx_ud[4];           /* User data window */
+       u32 tx_st[24];          /* Channel status data */
+};
+
+struct hal2_vol_regs {
+       u32 right;              /* Right volume */
+       u32 left;               /* Left volume */
+};
+
+struct hal2_syn_regs {
+       u32 _unused0[2];
+       u32 page;               /* DOC Page register */
+       u32 regsel;             /* DOC Register selection */
+       u32 dlow;               /* DOC Data low */
+       u32 dhigh;              /* DOC Data high */
+       u32 irq;                /* IRQ Status */
+       u32 dram;               /* DRAM Access */
+};
+
+#endif /* __HAL2_H */
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
new file mode 100644 (file)
index 0000000..4c63504
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ *   Sound driver for Silicon Graphics O2 Workstations A/V board audio.
+ *
+ *   Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org>
+ *   Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ *   Mxier part taken from mace_audio.c:
+ *   Copyright 2007 Thorben Jändling <tj.trevelyan@gmail.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/gfp.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/ip32/ip32_ints.h>
+#include <asm/ip32/mace.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+#include <sound/ad1843.h>
+
+
+MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org>");
+MODULE_DESCRIPTION("SGI O2 Audio");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Silicon Graphics, O2 Audio}}");
+
+static int index = SNDRV_DEFAULT_IDX1;  /* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1;   /* ID for this card */
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for SGI O2 soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for SGI O2 soundcard.");
+
+
+#define AUDIO_CONTROL_RESET              BIT(0) /* 1: reset audio interface */
+#define AUDIO_CONTROL_CODEC_PRESENT      BIT(1) /* 1: codec detected */
+
+#define CODEC_CONTROL_WORD_SHIFT        0
+#define CODEC_CONTROL_READ              BIT(16)
+#define CODEC_CONTROL_ADDRESS_SHIFT     17
+
+#define CHANNEL_CONTROL_RESET           BIT(10) /* 1: reset channel */
+#define CHANNEL_DMA_ENABLE              BIT(9)  /* 1: enable DMA transfer */
+#define CHANNEL_INT_THRESHOLD_DISABLED  (0 << 5) /* interrupt disabled */
+#define CHANNEL_INT_THRESHOLD_25        (1 << 5) /* int on buffer >25% full */
+#define CHANNEL_INT_THRESHOLD_50        (2 << 5) /* int on buffer >50% full */
+#define CHANNEL_INT_THRESHOLD_75        (3 << 5) /* int on buffer >75% full */
+#define CHANNEL_INT_THRESHOLD_EMPTY     (4 << 5) /* int on buffer empty */
+#define CHANNEL_INT_THRESHOLD_NOT_EMPTY (5 << 5) /* int on buffer !empty */
+#define CHANNEL_INT_THRESHOLD_FULL      (6 << 5) /* int on buffer empty */
+#define CHANNEL_INT_THRESHOLD_NOT_FULL  (7 << 5) /* int on buffer !empty */
+
+#define CHANNEL_RING_SHIFT              12
+#define CHANNEL_RING_SIZE               (1 << CHANNEL_RING_SHIFT)
+#define CHANNEL_RING_MASK               (CHANNEL_RING_SIZE - 1)
+
+#define CHANNEL_LEFT_SHIFT 40
+#define CHANNEL_RIGHT_SHIFT 8
+
+struct snd_sgio2audio_chan {
+       int idx;
+       struct snd_pcm_substream *substream;
+       int pos;
+       snd_pcm_uframes_t size;
+       spinlock_t lock;
+};
+
+/* definition of the chip-specific record */
+struct snd_sgio2audio {
+       struct snd_card *card;
+
+       /* codec */
+       struct snd_ad1843 ad1843;
+       spinlock_t ad1843_lock;
+
+       /* channels */
+       struct snd_sgio2audio_chan channel[3];
+
+       /* resources */
+       void *ring_base;
+       dma_addr_t ring_base_dma;
+};
+
+/* AD1843 access */
+
+/*
+ * read_ad1843_reg returns the current contents of a 16 bit AD1843 register.
+ *
+ * Returns unsigned register value on success, -errno on failure.
+ */
+static int read_ad1843_reg(void *priv, int reg)
+{
+       struct snd_sgio2audio *chip = priv;
+       int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->ad1843_lock, flags);
+
+       writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) |
+              CODEC_CONTROL_READ, &mace->perif.audio.codec_control);
+       wmb();
+       val = readq(&mace->perif.audio.codec_control); /* flush bus */
+       udelay(200);
+
+       val = readq(&mace->perif.audio.codec_read);
+
+       spin_unlock_irqrestore(&chip->ad1843_lock, flags);
+       return val;
+}
+
+/*
+ * write_ad1843_reg writes the specified value to a 16 bit AD1843 register.
+ */
+static int write_ad1843_reg(void *priv, int reg, int word)
+{
+       struct snd_sgio2audio *chip = priv;
+       int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->ad1843_lock, flags);
+
+       writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) |
+              (word << CODEC_CONTROL_WORD_SHIFT),
+              &mace->perif.audio.codec_control);
+       wmb();
+       val = readq(&mace->perif.audio.codec_control); /* flush bus */
+       udelay(200);
+
+       spin_unlock_irqrestore(&chip->ad1843_lock, flags);
+       return 0;
+}
+
+static int sgio2audio_gain_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = ad1843_get_gain_max(&chip->ad1843,
+                                            (int)kcontrol->private_value);
+       return 0;
+}
+
+static int sgio2audio_gain_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol);
+       int vol;
+
+       vol = ad1843_get_gain(&chip->ad1843, (int)kcontrol->private_value);
+
+       ucontrol->value.integer.value[0] = (vol >> 8) & 0xFF;
+       ucontrol->value.integer.value[1] = vol & 0xFF;
+
+       return 0;
+}
+
+static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol);
+       int newvol, oldvol;
+
+       oldvol = ad1843_get_gain(&chip->ad1843, kcontrol->private_value);
+       newvol = (ucontrol->value.integer.value[0] << 8) |
+               ucontrol->value.integer.value[1];
+
+       newvol = ad1843_set_gain(&chip->ad1843, kcontrol->private_value,
+               newvol);
+
+       return newvol != oldvol;
+}
+
+static int sgio2audio_source_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       static const char *texts[3] = {
+               "Cam Mic", "Mic", "Line"
+       };
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 3;
+       if (uinfo->value.enumerated.item >= 3)
+               uinfo->value.enumerated.item = 1;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int sgio2audio_source_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = ad1843_get_recsrc(&chip->ad1843);
+       return 0;
+}
+
+static int sgio2audio_source_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol);
+       int newsrc, oldsrc;
+
+       oldsrc = ad1843_get_recsrc(&chip->ad1843);
+       newsrc = ad1843_set_recsrc(&chip->ad1843,
+                                  ucontrol->value.enumerated.item[0]);
+
+       return newsrc != oldsrc;
+}
+
+/* dac1/pcm0 mixer control */
+static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "PCM Playback Volume",
+       .index          = 0,
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = AD1843_GAIN_PCM_0,
+       .info           = sgio2audio_gain_info,
+       .get            = sgio2audio_gain_get,
+       .put            = sgio2audio_gain_put,
+};
+
+/* dac2/pcm1 mixer control */
+static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "PCM Playback Volume",
+       .index          = 1,
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = AD1843_GAIN_PCM_1,
+       .info           = sgio2audio_gain_info,
+       .get            = sgio2audio_gain_get,
+       .put            = sgio2audio_gain_put,
+};
+
+/* record level mixer control */
+static struct snd_kcontrol_new sgio2audio_ctrl_reclevel __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Capture Volume",
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = AD1843_GAIN_RECLEV,
+       .info           = sgio2audio_gain_info,
+       .get            = sgio2audio_gain_get,
+       .put            = sgio2audio_gain_put,
+};
+
+/* record level source control */
+static struct snd_kcontrol_new sgio2audio_ctrl_recsource __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Capture Source",
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info           = sgio2audio_source_info,
+       .get            = sgio2audio_source_get,
+       .put            = sgio2audio_source_put,
+};
+
+/* line mixer control */
+static struct snd_kcontrol_new sgio2audio_ctrl_line __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Line Playback Volume",
+       .index          = 0,
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = AD1843_GAIN_LINE,
+       .info           = sgio2audio_gain_info,
+       .get            = sgio2audio_gain_get,
+       .put            = sgio2audio_gain_put,
+};
+
+/* cd mixer control */
+static struct snd_kcontrol_new sgio2audio_ctrl_cd __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Line Playback Volume",
+       .index          = 1,
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = AD1843_GAIN_LINE_2,
+       .info           = sgio2audio_gain_info,
+       .get            = sgio2audio_gain_get,
+       .put            = sgio2audio_gain_put,
+};
+
+/* mic mixer control */
+static struct snd_kcontrol_new sgio2audio_ctrl_mic __devinitdata = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "Mic Playback Volume",
+       .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .private_value  = AD1843_GAIN_MIC,
+       .info           = sgio2audio_gain_info,
+       .get            = sgio2audio_gain_get,
+       .put            = sgio2audio_gain_put,
+};
+
+
+static int __devinit snd_sgio2audio_new_mixer(struct snd_sgio2audio *chip)
+{
+       int err;
+
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_pcm0, chip));
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_pcm1, chip));
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_reclevel, chip));
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_recsource, chip));
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_line, chip));
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_cd, chip));
+       if (err < 0)
+               return err;
+
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&sgio2audio_ctrl_mic, chip));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/* low-level audio interface DMA */
+
+/* get data out of bounce buffer, count must be a multiple of 32 */
+/* returns 1 if a period has elapsed */
+static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip,
+                                       unsigned int ch, unsigned int count)
+{
+       int ret;
+       unsigned long src_base, src_pos, dst_mask;
+       unsigned char *dst_base;
+       int dst_pos;
+       u64 *src;
+       s16 *dst;
+       u64 x;
+       unsigned long flags;
+       struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime;
+
+       spin_lock_irqsave(&chip->channel[ch].lock, flags);
+
+       src_base = (unsigned long) chip->ring_base | (ch << CHANNEL_RING_SHIFT);
+       src_pos = readq(&mace->perif.audio.chan[ch].read_ptr);
+       dst_base = runtime->dma_area;
+       dst_pos = chip->channel[ch].pos;
+       dst_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1;
+
+       /* check if a period has elapsed */
+       chip->channel[ch].size += (count >> 3); /* in frames */
+       ret = chip->channel[ch].size >= runtime->period_size;
+       chip->channel[ch].size %= runtime->period_size;
+
+       while (count) {
+               src = (u64 *)(src_base + src_pos);
+               dst = (s16 *)(dst_base + dst_pos);
+
+               x = *src;
+               dst[0] = (x >> CHANNEL_LEFT_SHIFT) & 0xffff;
+               dst[1] = (x >> CHANNEL_RIGHT_SHIFT) & 0xffff;
+
+               src_pos = (src_pos + sizeof(u64)) & CHANNEL_RING_MASK;
+               dst_pos = (dst_pos + 2 * sizeof(s16)) & dst_mask;
+               count -= sizeof(u64);
+       }
+
+       writeq(src_pos, &mace->perif.audio.chan[ch].read_ptr); /* in bytes */
+       chip->channel[ch].pos = dst_pos;
+
+       spin_unlock_irqrestore(&chip->channel[ch].lock, flags);
+       return ret;
+}
+
+/* put some DMA data in bounce buffer, count must be a multiple of 32 */
+/* returns 1 if a period has elapsed */
+static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip,
+                                       unsigned int ch, unsigned int count)
+{
+       int ret;
+       s64 l, r;
+       unsigned long dst_base, dst_pos, src_mask;
+       unsigned char *src_base;
+       int src_pos;
+       u64 *dst;
+       s16 *src;
+       unsigned long flags;
+       struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime;
+
+       spin_lock_irqsave(&chip->channel[ch].lock, flags);
+
+       dst_base = (unsigned long)chip->ring_base | (ch << CHANNEL_RING_SHIFT);
+       dst_pos = readq(&mace->perif.audio.chan[ch].write_ptr);
+       src_base = runtime->dma_area;
+       src_pos = chip->channel[ch].pos;
+       src_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1;
+
+       /* check if a period has elapsed */
+       chip->channel[ch].size += (count >> 3); /* in frames */
+       ret = chip->channel[ch].size >= runtime->period_size;
+       chip->channel[ch].size %= runtime->period_size;
+
+       while (count) {
+               src = (s16 *)(src_base + src_pos);
+               dst = (u64 *)(dst_base + dst_pos);
+
+               l = src[0]; /* sign extend */
+               r = src[1]; /* sign extend */
+
+               *dst = ((l & 0x00ffffff) << CHANNEL_LEFT_SHIFT) |
+                       ((r & 0x00ffffff) << CHANNEL_RIGHT_SHIFT);
+
+               dst_pos = (dst_pos + sizeof(u64)) & CHANNEL_RING_MASK;
+               src_pos = (src_pos + 2 * sizeof(s16)) & src_mask;
+               count -= sizeof(u64);
+       }
+
+       writeq(dst_pos, &mace->perif.audio.chan[ch].write_ptr); /* in bytes */
+       chip->channel[ch].pos = src_pos;
+
+       spin_unlock_irqrestore(&chip->channel[ch].lock, flags);
+       return ret;
+}
+
+static int snd_sgio2audio_dma_start(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream);
+       struct snd_sgio2audio_chan *chan = substream->runtime->private_data;
+       int ch = chan->idx;
+
+       /* reset DMA channel */
+       writeq(CHANNEL_CONTROL_RESET, &mace->perif.audio.chan[ch].control);
+       udelay(10);
+       writeq(0, &mace->perif.audio.chan[ch].control);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* push a full buffer */
+               snd_sgio2audio_dma_push_frag(chip, ch, CHANNEL_RING_SIZE - 32);
+       }
+       /* set DMA to wake on 50% empty and enable interrupt */
+       writeq(CHANNEL_DMA_ENABLE | CHANNEL_INT_THRESHOLD_50,
+              &mace->perif.audio.chan[ch].control);
+       return 0;
+}
+
+static int snd_sgio2audio_dma_stop(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio_chan *chan = substream->runtime->private_data;
+
+       writeq(0, &mace->perif.audio.chan[chan->idx].control);
+       return 0;
+}
+
+static irqreturn_t snd_sgio2audio_dma_in_isr(int irq, void *dev_id)
+{
+       struct snd_sgio2audio_chan *chan = dev_id;
+       struct snd_pcm_substream *substream;
+       struct snd_sgio2audio *chip;
+       int count, ch;
+
+       substream = chan->substream;
+       chip = snd_pcm_substream_chip(substream);
+       ch = chan->idx;
+
+       /* empty the ring */
+       count = CHANNEL_RING_SIZE -
+               readq(&mace->perif.audio.chan[ch].depth) - 32;
+       if (snd_sgio2audio_dma_pull_frag(chip, ch, count))
+               snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t snd_sgio2audio_dma_out_isr(int irq, void *dev_id)
+{
+       struct snd_sgio2audio_chan *chan = dev_id;
+       struct snd_pcm_substream *substream;
+       struct snd_sgio2audio *chip;
+       int count, ch;
+
+       substream = chan->substream;
+       chip = snd_pcm_substream_chip(substream);
+       ch = chan->idx;
+       /* fill the ring */
+       count = CHANNEL_RING_SIZE -
+               readq(&mace->perif.audio.chan[ch].depth) - 32;
+       if (snd_sgio2audio_dma_push_frag(chip, ch, count))
+               snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t snd_sgio2audio_error_isr(int irq, void *dev_id)
+{
+       struct snd_sgio2audio_chan *chan = dev_id;
+       struct snd_pcm_substream *substream;
+
+       substream = chan->substream;
+       snd_sgio2audio_dma_stop(substream);
+       snd_sgio2audio_dma_start(substream);
+       return IRQ_HANDLED;
+}
+
+/* PCM part */
+/* PCM hardware definition */
+static struct snd_pcm_hardware snd_sgio2audio_pcm_hw = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_BLOCK_TRANSFER),
+       .formats =          SNDRV_PCM_FMTBIT_S16_BE,
+       .rates =            SNDRV_PCM_RATE_8000_48000,
+       .rate_min =         8000,
+       .rate_max =         48000,
+       .channels_min =     2,
+       .channels_max =     2,
+       .buffer_bytes_max = 65536,
+       .period_bytes_min = 32768,
+       .period_bytes_max = 65536,
+       .periods_min =      1,
+       .periods_max =      1024,
+};
+
+/* PCM playback open callback */
+static int snd_sgio2audio_playback1_open(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw = snd_sgio2audio_pcm_hw;
+       runtime->private_data = &chip->channel[1];
+       return 0;
+}
+
+static int snd_sgio2audio_playback2_open(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw = snd_sgio2audio_pcm_hw;
+       runtime->private_data = &chip->channel[2];
+       return 0;
+}
+
+/* PCM capture open callback */
+static int snd_sgio2audio_capture_open(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw = snd_sgio2audio_pcm_hw;
+       runtime->private_data = &chip->channel[0];
+       return 0;
+}
+
+/* PCM close callback */
+static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->private_data = NULL;
+       return 0;
+}
+
+
+/* hw_params callback */
+static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int size = params_buffer_bytes(hw_params);
+
+       /* alloc virtual 'dma' area */
+       if (runtime->dma_area)
+               vfree(runtime->dma_area);
+       runtime->dma_area = vmalloc(size);
+       if (runtime->dma_area == NULL)
+               return -ENOMEM;
+       runtime->dma_bytes = size;
+       return 0;
+}
+
+/* hw_free callback */
+static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       if (substream->runtime->dma_area)
+               vfree(substream->runtime->dma_area);
+       substream->runtime->dma_area = NULL;
+       return 0;
+}
+
+/* prepare callback */
+static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_sgio2audio_chan *chan = substream->runtime->private_data;
+       int ch = chan->idx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->channel[ch].lock, flags);
+
+       /* Setup the pseudo-dma transfer pointers.  */
+       chip->channel[ch].pos = 0;
+       chip->channel[ch].size = 0;
+       chip->channel[ch].substream = substream;
+
+       /* set AD1843 format */
+       /* hardware format is always S16_LE */
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               ad1843_setup_dac(&chip->ad1843,
+                                ch - 1,
+                                runtime->rate,
+                                SNDRV_PCM_FORMAT_S16_LE,
+                                runtime->channels);
+               break;
+       case SNDRV_PCM_STREAM_CAPTURE:
+               ad1843_setup_adc(&chip->ad1843,
+                                runtime->rate,
+                                SNDRV_PCM_FORMAT_S16_LE,
+                                runtime->channels);
+               break;
+       }
+       spin_unlock_irqrestore(&chip->channel[ch].lock, flags);
+       return 0;
+}
+
+/* trigger callback */
+static int snd_sgio2audio_pcm_trigger(struct snd_pcm_substream *substream,
+                                     int cmd)
+{
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* start the PCM engine */
+               snd_sgio2audio_dma_start(substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               /* stop the PCM engine */
+               snd_sgio2audio_dma_stop(substream);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* pointer callback */
+static snd_pcm_uframes_t
+snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream);
+       struct snd_sgio2audio_chan *chan = substream->runtime->private_data;
+
+       /* get the current hardware pointer */
+       return bytes_to_frames(substream->runtime,
+                              chip->channel[chan->idx].pos);
+}
+
+/* get the physical page pointer on the given offset */
+static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream,
+                                       unsigned long offset)
+{
+       return vmalloc_to_page(substream->runtime->dma_area + offset);
+}
+
+/* operators */
+static struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
+       .open =        snd_sgio2audio_playback1_open,
+       .close =       snd_sgio2audio_pcm_close,
+       .ioctl =       snd_pcm_lib_ioctl,
+       .hw_params =   snd_sgio2audio_pcm_hw_params,
+       .hw_free =     snd_sgio2audio_pcm_hw_free,
+       .prepare =     snd_sgio2audio_pcm_prepare,
+       .trigger =     snd_sgio2audio_pcm_trigger,
+       .pointer =     snd_sgio2audio_pcm_pointer,
+       .page =        snd_sgio2audio_page,
+};
+
+static struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
+       .open =        snd_sgio2audio_playback2_open,
+       .close =       snd_sgio2audio_pcm_close,
+       .ioctl =       snd_pcm_lib_ioctl,
+       .hw_params =   snd_sgio2audio_pcm_hw_params,
+       .hw_free =     snd_sgio2audio_pcm_hw_free,
+       .prepare =     snd_sgio2audio_pcm_prepare,
+       .trigger =     snd_sgio2audio_pcm_trigger,
+       .pointer =     snd_sgio2audio_pcm_pointer,
+       .page =        snd_sgio2audio_page,
+};
+
+static struct snd_pcm_ops snd_sgio2audio_capture_ops = {
+       .open =        snd_sgio2audio_capture_open,
+       .close =       snd_sgio2audio_pcm_close,
+       .ioctl =       snd_pcm_lib_ioctl,
+       .hw_params =   snd_sgio2audio_pcm_hw_params,
+       .hw_free =     snd_sgio2audio_pcm_hw_free,
+       .prepare =     snd_sgio2audio_pcm_prepare,
+       .trigger =     snd_sgio2audio_pcm_trigger,
+       .pointer =     snd_sgio2audio_pcm_pointer,
+       .page =        snd_sgio2audio_page,
+};
+
+/*
+ *  definitions of capture are omitted here...
+ */
+
+/* create a pcm device */
+static int __devinit snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       /* create first pcm device with one outputs and one input */
+       err = snd_pcm_new(chip->card, "SGI O2 Audio", 0, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       pcm->private_data = chip;
+       strcpy(pcm->name, "SGI O2 DAC1");
+
+       /* set operators */
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_sgio2audio_playback1_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_sgio2audio_capture_ops);
+
+       /* create second  pcm device with one outputs and no input */
+       err = snd_pcm_new(chip->card, "SGI O2 Audio", 1, 1, 0, &pcm);
+       if (err < 0)
+               return err;
+
+       pcm->private_data = chip;
+       strcpy(pcm->name, "SGI O2 DAC2");
+
+       /* set operators */
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_sgio2audio_playback2_ops);
+
+       return 0;
+}
+
+static struct {
+       int idx;
+       int irq;
+       irqreturn_t (*isr)(int, void *);
+       const char *desc;
+} snd_sgio2_isr_table[] = {
+       {
+               .idx = 0,
+               .irq = MACEISA_AUDIO1_DMAT_IRQ,
+               .isr = snd_sgio2audio_dma_in_isr,
+               .desc = "Capture DMA Channel 0"
+       }, {
+               .idx = 0,
+               .irq = MACEISA_AUDIO1_OF_IRQ,
+               .isr = snd_sgio2audio_error_isr,
+               .desc = "Capture Overflow"
+       }, {
+               .idx = 1,
+               .irq = MACEISA_AUDIO2_DMAT_IRQ,
+               .isr = snd_sgio2audio_dma_out_isr,
+               .desc = "Playback DMA Channel 1"
+       }, {
+               .idx = 1,
+               .irq = MACEISA_AUDIO2_MERR_IRQ,
+               .isr = snd_sgio2audio_error_isr,
+               .desc = "Memory Error Channel 1"
+       }, {
+               .idx = 2,
+               .irq = MACEISA_AUDIO3_DMAT_IRQ,
+               .isr = snd_sgio2audio_dma_out_isr,
+               .desc = "Playback DMA Channel 2"
+       }, {
+               .idx = 2,
+               .irq = MACEISA_AUDIO3_MERR_IRQ,
+               .isr = snd_sgio2audio_error_isr,
+               .desc = "Memory Error Channel 2"
+       }
+};
+
+/* ALSA driver */
+
+static int snd_sgio2audio_free(struct snd_sgio2audio *chip)
+{
+       int i;
+
+       /* reset interface */
+       writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control);
+       udelay(1);
+       writeq(0, &mace->perif.audio.control);
+
+       /* release IRQ's */
+       for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++)
+               free_irq(snd_sgio2_isr_table[i].irq,
+                        &chip->channel[snd_sgio2_isr_table[i].idx]);
+
+       dma_free_coherent(NULL, MACEISA_RINGBUFFERS_SIZE,
+                         chip->ring_base, chip->ring_base_dma);
+
+       /* release card data */
+       kfree(chip);
+       return 0;
+}
+
+static int snd_sgio2audio_dev_free(struct snd_device *device)
+{
+       struct snd_sgio2audio *chip = device->device_data;
+
+       return snd_sgio2audio_free(chip);
+}
+
+static struct snd_device_ops ops = {
+       .dev_free = snd_sgio2audio_dev_free,
+};
+
+static int __devinit snd_sgio2audio_create(struct snd_card *card,
+                                          struct snd_sgio2audio **rchip)
+{
+       struct snd_sgio2audio *chip;
+       int i, err;
+
+       *rchip = NULL;
+
+       /* check if a codec is attached to the interface */
+       /* (Audio or Audio/Video board present) */
+       if (!(readq(&mace->perif.audio.control) & AUDIO_CONTROL_CODEC_PRESENT))
+               return -ENOENT;
+
+       chip = kzalloc(sizeof(struct snd_sgio2audio), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->card = card;
+
+       chip->ring_base = dma_alloc_coherent(NULL, MACEISA_RINGBUFFERS_SIZE,
+                                            &chip->ring_base_dma, GFP_USER);
+       if (chip->ring_base == NULL) {
+               printk(KERN_ERR
+                      "sgio2audio: could not allocate ring buffers\n");
+               kfree(chip);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&chip->ad1843_lock);
+
+       /* initialize channels */
+       for (i = 0; i < 3; i++) {
+               spin_lock_init(&chip->channel[i].lock);
+               chip->channel[i].idx = i;
+       }
+
+       /* allocate IRQs */
+       for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) {
+               if (request_irq(snd_sgio2_isr_table[i].irq,
+                               snd_sgio2_isr_table[i].isr,
+                               0,
+                               snd_sgio2_isr_table[i].desc,
+                               &chip->channel[snd_sgio2_isr_table[i].idx])) {
+                       snd_sgio2audio_free(chip);
+                       printk(KERN_ERR "sgio2audio: cannot allocate irq %d\n",
+                              snd_sgio2_isr_table[i].irq);
+                       return -EBUSY;
+               }
+       }
+
+       /* reset the interface */
+       writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control);
+       udelay(1);
+       writeq(0, &mace->perif.audio.control);
+       msleep_interruptible(1); /* give time to recover */
+
+       /* set ring base */
+       writeq(chip->ring_base_dma, &mace->perif.ctrl.ringbase);
+
+       /* attach the AD1843 codec */
+       chip->ad1843.read = read_ad1843_reg;
+       chip->ad1843.write = write_ad1843_reg;
+       chip->ad1843.chip = chip;
+
+       /* initialize the AD1843 codec */
+       err = ad1843_init(&chip->ad1843);
+       if (err < 0) {
+               snd_sgio2audio_free(chip);
+               return err;
+       }
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_sgio2audio_free(chip);
+               return err;
+       }
+       *rchip = chip;
+       return 0;
+}
+
+static int __devinit snd_sgio2audio_probe(struct platform_device *pdev)
+{
+       struct snd_card *card;
+       struct snd_sgio2audio *chip;
+       int err;
+
+       card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (card == NULL)
+               return -ENOMEM;
+
+       err = snd_sgio2audio_create(card, &chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       snd_card_set_dev(card, &pdev->dev);
+
+       err = snd_sgio2audio_new_pcm(chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       err = snd_sgio2audio_new_mixer(chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "SGI O2 Audio");
+       strcpy(card->shortname, "SGI O2 Audio");
+       sprintf(card->longname, "%s irq %i-%i",
+               card->shortname,
+               MACEISA_AUDIO1_DMAT_IRQ,
+               MACEISA_AUDIO3_MERR_IRQ);
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       platform_set_drvdata(pdev, card);
+       return 0;
+}
+
+static int __exit snd_sgio2audio_remove(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+
+       snd_card_free(card);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver sgio2audio_driver = {
+       .probe  = snd_sgio2audio_probe,
+       .remove = __devexit_p(snd_sgio2audio_remove),
+       .driver = {
+               .name   = "sgio2audio",
+               .owner  = THIS_MODULE,
+       }
+};
+
+static int __init alsa_card_sgio2audio_init(void)
+{
+       return platform_driver_register(&sgio2audio_driver);
+}
+
+static void __exit alsa_card_sgio2audio_exit(void)
+{
+       platform_driver_unregister(&sgio2audio_driver);
+}
+
+module_init(alsa_card_sgio2audio_init)
+module_exit(alsa_card_sgio2audio_exit)
index 3be2dc1025b50592ef29f61e5480e4431a6de103..33940139844bf3893ab5487e711a728682c1c096 100644 (file)
@@ -7,7 +7,7 @@
 
 config SOUND_BCM_CS4297A
        tristate "Crystal Sound CS4297a (for Swarm)"
-       depends on SOUND_PRIME && SIBYTE_SWARM
+       depends on SIBYTE_SWARM
        help
          The BCM91250A has a Crystal CS4297a on synchronous serial
          port B (in addition to the DB-9 serial port).  Say Y or M
@@ -17,7 +17,7 @@ config SOUND_BCM_CS4297A
 
 config SOUND_VWSND
        tristate "SGI Visual Workstation Sound"
-       depends on SOUND_PRIME && X86_VISWS
+       depends on X86_VISWS
        help
          Say Y or M if you have an SGI Visual Workstation and you want to be
          able to use its on-board audio.  Read
@@ -26,19 +26,18 @@ config SOUND_VWSND
 
 config SOUND_HAL2
        tristate "SGI HAL2 sound (EXPERIMENTAL)"
-       depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL
+       depends on SGI_IP22 && EXPERIMENTAL
        help
          Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to
          use its on-board A2 audio system.
 
 config SOUND_AU1550_AC97
        tristate "Au1550/Au1200 AC97 Sound"
-       select SND_AC97_CODEC
-       depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200)
+       depends on SOC_AU1550 || SOC_AU1200
 
 config SOUND_TRIDENT
        tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
-       depends on SOUND_PRIME && PCI
+       depends on PCI
        ---help---
          Say Y or M if you have a PCI sound card utilizing the Trident
          4DWave-DX/NX chipset or your mother board chipset has SiS 7018
@@ -79,7 +78,7 @@ config SOUND_TRIDENT
 
 config SOUND_MSNDCLAS
        tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
-       depends on SOUND_PRIME && (m || !STANDALONE) && ISA
+       depends on (m || !STANDALONE) && ISA
        help
          Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
          Monterey (not for the Pinnacle or Fiji).
@@ -143,7 +142,7 @@ config MSNDCLAS_IO
 
 config SOUND_MSNDPIN
        tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji"
-       depends on SOUND_PRIME && (m || !STANDALONE) && ISA
+       depends on (m || !STANDALONE) && ISA
        help
          Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
          See <file:Documentation/sound/oss/MultiSound> for important information
@@ -229,7 +228,7 @@ config MSNDPIN_NONPNP
          configure the card's resources.
 
 comment "MSND Pinnacle DSP section will be configured to above parameters."
-       depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP
+       depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP
 
 config MSNDPIN_CFG
        hex "MSND Pinnacle config port 250,260,270"
@@ -242,7 +241,7 @@ config MSNDPIN_CFG
          Mode".
 
 comment "Pinnacle-specific Device Configuration (0 disables)"
-       depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP
+       depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP
 
 config MSNDPIN_MPU_IO
        hex "MSND Pinnacle MPU I/O (e.g. 330)"
@@ -294,7 +293,7 @@ config MSNDPIN_JOYSTICK_IO
 
 config MSND_FIFOSIZE
        int "MSND buffer size (kB)"
-       depends on SOUND_PRIME && (SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y)
+       depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y
        default "128"
        help
          Configures the size of each audio buffer, in kilobytes, for
@@ -302,9 +301,9 @@ config MSND_FIFOSIZE
          and Pinnacle). Larger values reduce the chance of data overruns at
          the expense of overall latency. If unsure, use the default.
 
-config SOUND_OSS
+menuconfig SOUND_OSS
        tristate "OSS sound modules"
-       depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS
+       depends on ISA_DMA_API && VIRT_TO_BUS
        help
          OSS is the Open Sound System suite of sound card drivers.  They make
          sound programming easier since they provide a common API.  Say Y or
@@ -312,16 +311,16 @@ config SOUND_OSS
          driver for your sound card above, then pick your driver from the
          list below.
 
+if SOUND_OSS
+
 config SOUND_TRACEINIT
        bool "Verbose initialisation"
-       depends on SOUND_OSS
        help
          Verbose soundcard initialization -- affects the format of autoprobe
          and initialization messages at boot time.
 
 config SOUND_DMAP
        bool "Persistent DMA buffers"
-       depends on SOUND_OSS
        ---help---
          Linux can often have problems allocating DMA buffers for ISA sound
          cards on machines with more than 16MB of RAM. This is because ISA
@@ -338,8 +337,6 @@ config SOUND_DMAP
 
 config SOUND_SSCAPE
        tristate "Ensoniq SoundScape support"
-       depends on SOUND_OSS
-       depends on VIRT_TO_BUS
        help
          Answer Y if you have a sound card based on the Ensoniq SoundScape
          chipset. Such cards are being manufactured at least by Ensoniq, Spea
@@ -352,13 +349,11 @@ config SOUND_SSCAPE
 
 config SOUND_VMIDI
        tristate "Loopback MIDI device support"
-       depends on SOUND_OSS
        help
          Support for MIDI loopback on port 1 or 2.
 
 config SOUND_TRIX
        tristate "MediaTrix AudioTrix Pro support"
-       depends on SOUND_OSS
        help
          Answer Y if you have the AudioTriX Pro sound card manufactured
          by MediaTrix.
@@ -382,7 +377,6 @@ config TRIX_BOOT_FILE
 
 config SOUND_MSS
        tristate "Microsoft Sound System support"
-       depends on SOUND_OSS
        ---help---
          Again think carefully before answering Y to this question.  It's
          safe to answer Y if you have the original Windows Sound System card
@@ -414,7 +408,6 @@ config SOUND_MSS
 
 config SOUND_MPU401
        tristate "MPU-401 support (NOT for SB16)"
-       depends on SOUND_OSS
        ---help---
          Be careful with this question.  The MPU401 interface is supported by
          all sound cards.  However, some natively supported cards have their
@@ -430,7 +423,6 @@ config SOUND_MPU401
 
 config SOUND_PAS
        tristate "ProAudioSpectrum 16 support"
-       depends on SOUND_OSS
        ---help---
          Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
          16 or Logitech SoundMan 16 sound card. Answer N if you have some
@@ -452,7 +444,6 @@ config PAS_JOYSTICK
 
 config SOUND_PSS
        tristate "PSS (AD1848, ADSP-2115, ESC614) support"
-       depends on SOUND_OSS
        help
          Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
          ADSP-16 or some other card based on the PSS chipset (AD1848 codec +
@@ -495,7 +486,6 @@ config PSS_BOOT_FILE
 
 config SOUND_SB
        tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
-       depends on SOUND_OSS
        ---help---
          Answer Y if you have an original Sound Blaster card made by Creative
          Labs or a 100% hardware compatible clone (like the Thunderboard or
@@ -522,7 +512,6 @@ config SOUND_SB
 
 config SOUND_YM3812
        tristate "Yamaha FM synthesizer (YM3812/OPL-3) support"
-       depends on SOUND_OSS
        ---help---
          Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
          Answering Y is usually a safe and recommended choice, however some
@@ -538,7 +527,6 @@ config SOUND_YM3812
 
 config SOUND_UART6850
        tristate "6850 UART support"
-       depends on SOUND_OSS
        help
          This option enables support for MIDI interfaces based on the 6850
          UART chip. This interface is rarely found on sound cards. It's safe
@@ -549,7 +537,6 @@ config SOUND_UART6850
 
 config SOUND_AEDSP16
        tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)"
-       depends on SOUND_OSS
        ---help---
          Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
          driver supports Audio Excel DSP 16 but not the III nor PnP versions
@@ -630,14 +617,14 @@ endchoice
 
 config SOUND_VIDC
        tristate "VIDC 16-bit sound"
-       depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) && SOUND_OSS
+       depends on ARM && (ARCH_ACORN || ARCH_CLPS7500)
        help
          16-bit support for the VIDC onboard sound hardware found on Acorn
          machines.
 
 config SOUND_WAVEARTIST
        tristate "Netwinder WaveArtist"
-       depends on ARM && SOUND_OSS && ARCH_NETWINDER
+       depends on ARM && ARCH_NETWINDER
        help
          Say Y here to include support for the Rockwell WaveArtist sound
          system.  This driver is mainly for the NetWinder.
@@ -646,9 +633,11 @@ config SOUND_KAHLUA
        tristate "XpressAudio Sound Blaster emulation"
        depends on SOUND_SB
 
+endif  # SOUND_OSS
+
 config SOUND_SH_DAC_AUDIO
        tristate "SuperH DAC audio support"
-       depends on SOUND_PRIME && CPU_SH3
+       depends on CPU_SH3
 
 config SOUND_SH_DAC_AUDIO_CHANNEL
        int "DAC channel"
index a003c0ea9303f800f27e6de612773d0a2f5012e2..95fc5c681755eafff96d7165c1eeb3b9da72a781 100644 (file)
@@ -211,10 +211,6 @@ static int state_unit = -1;
 static int irq_installed;
 #endif /* MODULE */
 
-/* software implemented recording volume! */
-uint software_input_volume = SW_INPUT_VOLUME_SCALE * SW_INPUT_VOLUME_DEFAULT;
-EXPORT_SYMBOL(software_input_volume);
-
 /* control over who can modify resources shared between play/record */
 static mode_t shared_resource_owner;
 static int shared_resources_initialised;
@@ -1188,7 +1184,7 @@ static struct {
 
 /* publish this function for use by low-level code, if required */
 
-char *get_afmt_string(int afmt)
+static char *get_afmt_string(int afmt)
 {
         switch(afmt) {
             case AFMT_MU_LAW:
@@ -1551,4 +1547,3 @@ EXPORT_SYMBOL(dmasound_catchRadius);
 EXPORT_SYMBOL(dmasound_ulaw2dma8);
 EXPORT_SYMBOL(dmasound_alaw2dma8);
 #endif
-EXPORT_SYMBOL(get_afmt_string) ;
index 202e8103dc4da39bffe0d740ae56bef1de2a2ceb..06e9e88e4c05dd9e0735279fd9d4356163034224 100644 (file)
@@ -710,7 +710,7 @@ static MACHINE machAmiga = {
 /*** Config & Setup **********************************************************/
 
 
-int __init dmasound_paula_init(void)
+static int __init dmasound_paula_init(void)
 {
        int err;
 
index b3379dd7ca5e1d49d5cc8d0a13c533b891ef8875..1855b14d90c3922989abfd43a0e53b57423174f6 100644 (file)
@@ -611,7 +611,7 @@ static MACHINE machQ40 = {
 /*** Config & Setup **********************************************************/
 
 
-int __init dmasound_q40_init(void)
+static int __init dmasound_q40_init(void)
 {
        if (MACH_IS_Q40) {
            dmasound.mach = machQ40;
index ba38d6200099f883f3f188d6e9255bf07afa80b6..e4282d93a1aaa121aaac6eeac5c9f22cd92083ec 100644 (file)
@@ -20,8 +20,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $
- *
  ********************************************************************/
 
 #include <linux/module.h>
index d0ca582c4583e302f171c21e653ea4e5c43f7959..61b3955481c56da1f7b88ca2ac43fd08ed5ef15a 100644 (file)
@@ -24,8 +24,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $
- *
  ********************************************************************/
 #ifndef __MSND_H
 #define __MSND_H
index 7ffea5267f9699dd4ca22aa2557f1ca777505c91..1a17dde2f650ea04f14cafd68b7cd8cd086c027b 100644 (file)
@@ -24,8 +24,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * 
- * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $
- *
  ********************************************************************/
 #ifndef __MSND_CLASSIC_H
 #define __MSND_CLASSIC_H
index f1f49ebf752ea0a6ee109fbf9622b1a0265c92f0..bf27e008f465f29aed345549b583c3e7dcb75213 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd_pinnacle.c,v 1.8 2000/12/30 00:33:21 sycamore Exp $
- *
  * 12-3-2000  Modified IO port validation  Steve Sycamore
  *
- *
- * $$$: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv $$$ $
- *
  ********************************************************************/
 
 #include <linux/kernel.h>
index cce91148700481b1ac28aa67729311d0ebcbf2e5..c18d66cbbe3fdb0d235174e2f768acf6e34e3918 100644 (file)
@@ -24,8 +24,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $
- *
  ********************************************************************/
 #ifndef __MSND_PINNACLE_H
 #define __MSND_PINNACLE_H
index 2c5aaa58046d8895bc25c48d7171706596f464a8..dcbb3f739e61ee801b39ebfd5ace060a53f19098 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
-#include <asm/mach-visws/cobalt.h>
+#include <asm/visws/cobalt.h>
 
 #include "sound_config.h"
 
index a5a7f9d75d051e37398b094a2e42100adbf19029..9b61d95010f07134e481eed1a481d77d13d8ca88 100644 (file)
@@ -1,15 +1,20 @@
 # ALSA PA-RISC drivers
 
-menu "GSC devices"
-       depends on SND!=n && GSC
+menuconfig SND_GSC
+       bool "GSC sound devices"
+       depends on GSC
+       default y
+       help
+         Support for GSC sound devices on PA-RISC architectures.
+
+if SND_GSC
 
 config SND_HARMONY
        tristate "Harmony/Vivace sound chip"
-       depends on SND
        select SND_PCM
        help
          Say 'Y' or 'M' to include support for the Harmony/Vivace sound
          chip found in most GSC-based PA-RISC workstations.  It's frequently
          provided as part of the Lasi multi-function IC.
 
-endmenu
+endif  # SND_GSC
index 7e47421095726afd72650cffe20e2306aebfa252..8fe5dac3942824a8c9274eb1ce0dea74e80f8e99 100644 (file)
@@ -1,11 +1,16 @@
 # ALSA PCI drivers
 
-menu "PCI devices"
-       depends on SND!=n && PCI
+menuconfig SND_PCI
+       bool "PCI sound devices"
+       depends on PCI
+       default y
+       help
+         Support for sound devices connected via the PCI bus.
+
+if SND_PCI
 
 config SND_AD1889
        tristate "Analog Devices AD1889"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated AC97 sound
@@ -17,7 +22,6 @@ config SND_AD1889
 
 config SND_ALS300
        tristate "Avance Logic ALS300/ALS300+"
-       depends on SND
        select SND_PCM
        select SND_AC97_CODEC
        select SND_OPL3_LIB
@@ -29,7 +33,7 @@ config SND_ALS300
 
 config SND_ALS4000
        tristate "Avance Logic ALS4000"
-       depends on SND && ISA_DMA_API
+       depends on ISA_DMA_API
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -43,7 +47,6 @@ config SND_ALS4000
 
 config SND_ALI5451
        tristate "ALi M5451 PCI Audio Controller"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -57,7 +60,6 @@ config SND_ALI5451
 
 config SND_ATIIXP
        tristate "ATI IXP AC97 Controller"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated AC97 sound
@@ -69,7 +71,6 @@ config SND_ATIIXP
 
 config SND_ATIIXP_MODEM
        tristate "ATI IXP Modem"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated MC97 modem on
@@ -80,7 +81,6 @@ config SND_ATIIXP_MODEM
 
 config SND_AU8810
        tristate "Aureal Advantage"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -95,7 +95,6 @@ config SND_AU8810
 
 config SND_AU8820
        tristate "Aureal Vortex"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -109,7 +108,6 @@ config SND_AU8820
 
 config SND_AU8830
        tristate "Aureal Vortex 2"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -124,7 +122,6 @@ config SND_AU8830
 
 config SND_AW2
        tristate "Emagic Audiowerk 2"
-       depends on SND
        help
          Say Y here to include support for Emagic Audiowerk 2 soundcards.
 
@@ -139,7 +136,7 @@ config SND_AW2
 
 config SND_AZT3328
        tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)"
-       depends on SND && EXPERIMENTAL
+       depends on EXPERIMENTAL
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -152,7 +149,6 @@ config SND_AZT3328
 
 config SND_BT87X
        tristate "Bt87x Audio Capture"
-       depends on SND
        select SND_PCM
        help
          If you want to record audio from TV cards based on
@@ -174,7 +170,6 @@ config SND_BT87X_OVERCLOCK
 
 config SND_CA0106
        tristate "SB Audigy LS / Live 24bit"
-       depends on SND
        select SND_AC97_CODEC
        select SND_RAWMIDI
        select SND_VMASTER
@@ -187,7 +182,6 @@ config SND_CA0106
 
 config SND_CMIPCI
        tristate "C-Media 8338, 8738, 8768, 8770"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
@@ -201,13 +195,11 @@ config SND_CMIPCI
 
 config SND_OXYGEN_LIB
         tristate
-       depends on SND
        select SND_PCM
        select SND_MPU401_UART
 
 config SND_OXYGEN
        tristate "C-Media 8788 (Oxygen)"
-       depends on SND
        select SND_OXYGEN_LIB
        help
          Say Y here to include support for sound cards based on the
@@ -225,7 +217,6 @@ config SND_OXYGEN
 
 config SND_CS4281
        tristate "Cirrus Logic (Sound Fusion) CS4281"
-       depends on SND
        select SND_OPL3_LIB
        select SND_RAWMIDI
        select SND_AC97_CODEC
@@ -237,7 +228,6 @@ config SND_CS4281
 
 config SND_CS46XX
        tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
-       depends on SND
        select SND_RAWMIDI
        select SND_AC97_CODEC
        help
@@ -258,7 +248,7 @@ config SND_CS46XX_NEW_DSP
 
 config SND_CS5530
        tristate "CS5530 Audio"
-       depends on SND && ISA_DMA_API
+       depends on ISA_DMA_API
        select SND_SB16_DSP
        help
          Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
@@ -268,7 +258,7 @@ config SND_CS5530
 
 config SND_CS5535AUDIO
        tristate "CS5535/CS5536 Audio"
-       depends on SND && X86 && !X86_64
+       depends on X86 && !X86_64
        select SND_PCM
        select SND_AC97_CODEC
        help
@@ -286,7 +276,6 @@ config SND_CS5535AUDIO
 
 config SND_DARLA20
        tristate "(Echoaudio) Darla20"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -297,7 +286,6 @@ config SND_DARLA20
 
 config SND_GINA20
        tristate "(Echoaudio) Gina20"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -308,7 +296,6 @@ config SND_GINA20
 
 config SND_LAYLA20
        tristate "(Echoaudio) Layla20"
-       depends on SND
        select FW_LOADER
        select SND_RAWMIDI
        select SND_PCM
@@ -320,7 +307,6 @@ config SND_LAYLA20
 
 config SND_DARLA24
        tristate "(Echoaudio) Darla24"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -331,7 +317,6 @@ config SND_DARLA24
 
 config SND_GINA24
        tristate "(Echoaudio) Gina24"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -342,7 +327,6 @@ config SND_GINA24
 
 config SND_LAYLA24
        tristate "(Echoaudio) Layla24"
-       depends on SND
        select FW_LOADER
        select SND_RAWMIDI
        select SND_PCM
@@ -354,7 +338,6 @@ config SND_LAYLA24
 
 config SND_MONA
        tristate "(Echoaudio) Mona"
-       depends on SND
        select FW_LOADER
        select SND_RAWMIDI
        select SND_PCM
@@ -366,7 +349,6 @@ config SND_MONA
 
 config SND_MIA
        tristate "(Echoaudio) Mia"
-       depends on SND
        select FW_LOADER
        select SND_RAWMIDI
        select SND_PCM
@@ -378,7 +360,6 @@ config SND_MIA
 
 config SND_ECHO3G
        tristate "(Echoaudio) 3G cards"
-       depends on SND
        select FW_LOADER
        select SND_RAWMIDI
        select SND_PCM
@@ -390,7 +371,6 @@ config SND_ECHO3G
 
 config SND_INDIGO
        tristate "(Echoaudio) Indigo"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -401,7 +381,6 @@ config SND_INDIGO
 
 config SND_INDIGOIO
        tristate "(Echoaudio) Indigo IO"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -412,7 +391,6 @@ config SND_INDIGOIO
 
 config SND_INDIGODJ
        tristate "(Echoaudio) Indigo DJ"
-       depends on SND
        select FW_LOADER
        select SND_PCM
        help
@@ -423,7 +401,6 @@ config SND_INDIGODJ
 
 config SND_EMU10K1
        tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
-       depends on SND
        select FW_LOADER
        select SND_HWDEP
        select SND_RAWMIDI
@@ -441,7 +418,6 @@ config SND_EMU10K1
 
 config SND_EMU10K1X
        tristate "Emu10k1X (Dell OEM Version)"
-       depends on SND
        select SND_AC97_CODEC
        select SND_RAWMIDI
        help
@@ -453,7 +429,6 @@ config SND_EMU10K1X
 
 config SND_ENS1370
        tristate "(Creative) Ensoniq AudioPCI 1370"
-       depends on SND
        select SND_RAWMIDI
        select SND_PCM
        help
@@ -464,7 +439,6 @@ config SND_ENS1370
 
 config SND_ENS1371
        tristate "(Creative) Ensoniq AudioPCI 1371/1373"
-       depends on SND
        select SND_RAWMIDI
        select SND_AC97_CODEC
        help
@@ -476,7 +450,6 @@ config SND_ENS1371
 
 config SND_ES1938
        tristate "ESS ES1938/1946/1969 (Solo-1)"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_AC97_CODEC
@@ -489,7 +462,6 @@ config SND_ES1938
 
 config SND_ES1968
        tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -501,7 +473,6 @@ config SND_ES1968
 
 config SND_FM801
        tristate "ForteMedia FM801"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_AC97_CODEC
@@ -528,7 +499,6 @@ config SND_FM801_TEA575X
 
 config SND_HDA_INTEL
        tristate "Intel HD Audio"
-       depends on SND
        select SND_PCM
        select SND_VMASTER
        help
@@ -637,7 +607,6 @@ config SND_HDA_POWER_SAVE_DEFAULT
 
 config SND_HDSP
        tristate "RME Hammerfall DSP Audio"
-       depends on SND
        select SND_HWDEP
        select SND_RAWMIDI
        select SND_PCM
@@ -650,7 +619,6 @@ config SND_HDSP
 
 config SND_HDSPM
        tristate "RME Hammerfall DSP MADI"
-       depends on SND
        select SND_HWDEP
        select SND_RAWMIDI
        select SND_PCM
@@ -663,7 +631,6 @@ config SND_HDSPM
 
 config SND_HIFIER
        tristate "TempoTec HiFier Fantasia"
-       depends on SND
        select SND_OXYGEN_LIB
        help
          Say Y here to include support for the MediaTek/TempoTec HiFier
@@ -674,7 +641,6 @@ config SND_HIFIER
 
 config SND_ICE1712
        tristate "ICEnsemble ICE1712 (Envy24)"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -691,8 +657,7 @@ config SND_ICE1712
 
 config SND_ICE1724
        tristate "ICE/VT1724/1720 (Envy24HT/PT)"
-       depends on SND
-       select SND_MPU401_UART
+       select SND_RAWMIDI
        select SND_AC97_CODEC
        select SND_VMASTER
        help
@@ -709,7 +674,6 @@ config SND_ICE1724
 
 config SND_INTEL8X0
        tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated AC97 sound
@@ -722,7 +686,6 @@ config SND_INTEL8X0
 
 config SND_INTEL8X0M
        tristate "Intel/SiS/nVidia/AMD MC97 Modem"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated MC97 modem on
@@ -733,7 +696,6 @@ config SND_INTEL8X0M
 
 config SND_KORG1212
        tristate "Korg 1212 IO"
-       depends on SND
        select FW_LOADER if !SND_KORG1212_FIRMWARE_IN_KERNEL
        select SND_PCM
        help
@@ -753,7 +715,6 @@ config SND_KORG1212_FIRMWARE_IN_KERNEL
 
 config SND_MAESTRO3
        tristate "ESS Allegro/Maestro3"
-       depends on SND
        select FW_LOADER if !SND_MAESTRO3_FIRMWARE_IN_KERNEL
        select SND_AC97_CODEC
        help
@@ -774,7 +735,6 @@ config SND_MAESTRO3_FIRMWARE_IN_KERNEL
 
 config SND_MIXART
        tristate "Digigram miXart"
-       depends on SND
        select SND_HWDEP
        select SND_PCM
        help
@@ -786,7 +746,6 @@ config SND_MIXART
 
 config SND_NM256
        tristate "NeoMagic NM256AV/ZX"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for NeoMagic NM256AV/ZX chips.
@@ -796,7 +755,6 @@ config SND_NM256
 
 config SND_PCXHR
        tristate "Digigram PCXHR"
-       depends on SND
        select SND_PCM
        select SND_HWDEP
        help
@@ -807,7 +765,6 @@ config SND_PCXHR
 
 config SND_RIPTIDE
        tristate "Conexant Riptide"
-       depends on SND
        select FW_LOADER
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -820,7 +777,6 @@ config SND_RIPTIDE
 
 config SND_RME32
        tristate "RME Digi32, 32/8, 32 PRO"
-       depends on SND
        select SND_PCM
        help
          Say Y to include support for RME Digi32, Digi32 PRO and
@@ -832,7 +788,6 @@ config SND_RME32
 
 config SND_RME96
        tristate "RME Digi96, 96/8, 96/8 PRO"
-       depends on SND
        select SND_PCM
        help
          Say Y here to include support for RME Digi96, Digi96/8 and
@@ -843,7 +798,6 @@ config SND_RME96
 
 config SND_RME9652
        tristate "RME Digi9652 (Hammerfall)"
-       depends on SND
        select SND_PCM
        help
          Say Y here to include support for RME Hammerfall (RME
@@ -854,7 +808,7 @@ config SND_RME9652
 
 config SND_SIS7019
        tristate "SiS 7019 Audio Accelerator"
-       depends on SND && X86 && !X86_64
+       depends on X86 && !X86_64
        select SND_AC97_CODEC
        help
          Say Y here to include support for the SiS 7019 Audio Accelerator.
@@ -864,7 +818,6 @@ config SND_SIS7019
 
 config SND_SONICVIBES
        tristate "S3 SonicVibes"
-       depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_AC97_CODEC
@@ -877,7 +830,6 @@ config SND_SONICVIBES
 
 config SND_TRIDENT
        tristate "Trident 4D-Wave DX/NX; SiS 7018"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -889,7 +841,6 @@ config SND_TRIDENT
 
 config SND_VIA82XX
        tristate "VIA 82C686A/B, 8233/8235 AC97 Controller"
-       depends on SND
        select SND_MPU401_UART
        select SND_AC97_CODEC
        help
@@ -901,7 +852,6 @@ config SND_VIA82XX
 
 config SND_VIA82XX_MODEM
        tristate "VIA 82C686A/B, 8233 based Modems"
-       depends on SND
        select SND_AC97_CODEC
        help
          Say Y here to include support for the integrated MC97 modem on
@@ -912,7 +862,6 @@ config SND_VIA82XX_MODEM
 
 config SND_VIRTUOSO
        tristate "Asus Virtuoso 100/200 (Xonar)"
-       depends on SND
        select SND_OXYGEN_LIB
        help
          Say Y here to include support for sound cards based on the
@@ -923,7 +872,6 @@ config SND_VIRTUOSO
 
 config SND_VX222
        tristate "Digigram VX222"
-       depends on SND
        select SND_VX_LIB
        help
          Say Y here to include support for Digigram VX222 soundcards.
@@ -933,7 +881,6 @@ config SND_VX222
 
 config SND_YMFPCI
        tristate "Yamaha YMF724/740/744/754"
-       depends on SND
        select FW_LOADER if !SND_YMFPCI_FIRMWARE_IN_KERNEL
        select SND_OPL3_LIB
        select SND_MPU401_UART
@@ -954,25 +901,4 @@ config SND_YMFPCI_FIRMWARE_IN_KERNEL
          for the YMFPCI driver.  If you choose N here, you need to
          install the firmware files from the alsa-firmware package.
 
-config SND_AC97_POWER_SAVE
-       bool "AC97 Power-Saving Mode"
-       depends on SND_AC97_CODEC && EXPERIMENTAL
-       default n
-       help
-         Say Y here to enable the aggressive power-saving support of
-         AC97 codecs.  In this mode, the power-mode is dynamically
-         controlled at each open/close.
-
-         The mode is activated by passing power_save=1 option to
-         snd-ac97-codec driver.  You can toggle it dynamically over
-         sysfs, too.
-
-config SND_AC97_POWER_SAVE_DEFAULT
-       int "Default time-out for AC97 power-save mode"
-       depends on SND_AC97_POWER_SAVE
-       default 0
-       help
-         The default time-out value in seconds for AC97 automatic
-         power-save mode.  0 means to disable the power-save mode.
-
-endmenu
+endif  # SND_PCI
index 85ef14bc805649611b51873d8ff7de6de9ba4d6c..65b25d221cd2795135f265dcbb05d47f1dfc8a8f 100644 (file)
@@ -13,7 +13,7 @@ snd-bt87x-objs := bt87x.o
 snd-cmipci-objs := cmipci.o
 snd-cs4281-objs := cs4281.o
 snd-cs5530-objs := cs5530.o
-snd-ens1370-objs := ens1370.o
+snd-ens1370-objs := ens1370.o ak4531_codec.o
 snd-ens1371-objs := ens1371.o
 snd-es1938-objs := es1938.o
 snd-es1968-objs := es1968.o
index 0be48b1a22d04c018e1434d9710b0f8981468466..41fa322f0971677382fcb9ab3ba94492139ee20c 100644 (file)
@@ -3,16 +3,8 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o
-
-ifneq ($(CONFIG_PROC_FS),)
-snd-ac97-codec-objs += ac97_proc.o
-endif
-
-snd-ak4531-codec-objs := ak4531_codec.o
+snd-ac97-codec-y := ac97_codec.o ac97_pcm.o
+snd-ac97-codec-$(CONFIG_PROC_FS) += ac97_proc.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
-obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
-
-obj-m := $(sort $(obj-m))
index 45fd29017ddd59ded7e731ece20c977a4a4bde20..07364c00768a4dd90f8eceeb338d899955a17685 100644 (file)
@@ -49,8 +49,9 @@ MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
 
 #ifdef CONFIG_SND_AC97_POWER_SAVE
 static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT;
-module_param(power_save, bool, 0644);
-MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control");
+module_param(power_save, int, 0644);
+MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
+                "(in second, 0 = disable).");
 #endif
 /*
 
@@ -2294,9 +2295,11 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97)
        power |= AC97_PD_PR0 | AC97_PD_PR1;     /* ADC & DAC powerdown */
        snd_ac97_write(ac97, AC97_POWERDOWN, power);
        udelay(100);
-       power |= AC97_PD_PR2 | AC97_PD_PR3;     /* Analog Mixer powerdown */
+       power |= AC97_PD_PR2;   /* Analog Mixer powerdown (Vref on) */
        snd_ac97_write(ac97, AC97_POWERDOWN, power);
        if (ac97_is_power_save_mode(ac97)) {
+               power |= AC97_PD_PR3;   /* Analog Mixer powerdown */
+               snd_ac97_write(ac97, AC97_POWERDOWN, power);
                udelay(100);
                /* AC-link powerdown, internal Clk disable */
                /* FIXME: this may cause click noises on some boards */
@@ -2362,7 +2365,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
                 *  that open/close frequently)
                 */
                schedule_delayed_work(&ac97->power_work,
-                                     msecs_to_jiffies(2000));
+                                     msecs_to_jiffies(power_save * 1000));
        else {
                cancel_delayed_work(&ac97->power_work);
                update_power_regs(ac97);
index 1292dcee072df21b34aa39daecaee841a429dfe0..0746e9ccc20b1572ec1cae300b0178c1ad6f90e9 100644 (file)
@@ -669,6 +669,7 @@ AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
 AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
 AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
 
+AC97_SINGLE("Master Left Inv Switch", AC97_MASTER, 6, 1, 0),
 AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
 AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0),
 AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
@@ -3352,8 +3353,66 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),
 AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),
 };
 
+static const char *slave_vols_vt1616[] = {
+       "Front Playback Volume",
+       "Surround Playback Volume",
+       "Center Playback Volume",
+       "LFE Playback Volume",
+       NULL
+};
+
+static const char *slave_sws_vt1616[] = {
+       "Front Playback Switch",
+       "Surround Playback Switch",
+       "Center Playback Switch",
+       "LFE Playback Switch",
+       NULL
+};
+
+/* find a mixer control element with the given name */
+static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
+                                                   const char *name)
+{
+       struct snd_ctl_elem_id id;
+       memset(&id, 0, sizeof(id));
+       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       strcpy(id.name, name);
+       return snd_ctl_find_id(ac97->bus->card, &id);
+}
+
+/* create a virtual master control and add slaves */
+int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
+                        const unsigned int *tlv, const char **slaves)
+{
+       struct snd_kcontrol *kctl;
+       const char **s;
+       int err;
+
+       kctl = snd_ctl_make_virtual_master(name, tlv);
+       if (!kctl)
+               return -ENOMEM;
+       err = snd_ctl_add(ac97->bus->card, kctl);
+       if (err < 0)
+               return err;
+
+       for (s = slaves; *s; s++) {
+               struct snd_kcontrol *sctl;
+
+               sctl = snd_ac97_find_mixer_ctl(ac97, *s);
+               if (!sctl) {
+                       snd_printdd("Cannot find slave %s, skipped\n", *s);
+                       continue;
+               }
+               err = snd_ctl_add_slave(kctl, sctl);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
 static int patch_vt1616_specific(struct snd_ac97 * ac97)
 {
+       struct snd_kcontrol *kctl;
        int err;
 
        if (snd_ac97_try_bit(ac97, 0x5a, 9))
@@ -3361,6 +3420,24 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97)
                        return err;
        if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0)
                return err;
+
+       /* There is already a misnamed master switch.  Rename it.  */
+       kctl = snd_ac97_find_mixer_ctl(ac97, "Master Playback Volume");
+       if (!kctl)
+               return -EINVAL;
+
+       snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Front Playback");
+
+       err = snd_ac97_add_vmaster(ac97, "Master Playback Volume",
+                                  kctl->tlv.p, slave_vols_vt1616);
+       if (err < 0)
+               return err;
+
+       err = snd_ac97_add_vmaster(ac97, "Master Playback Switch",
+                                  NULL, slave_sws_vt1616);
+       if (err < 0)
+               return err;
+
        return 0;
 }
 
@@ -3633,7 +3710,7 @@ static int patch_ucb1400(struct snd_ac97 * ac97)
 {
        ac97->build_ops = &patch_ucb1400_ops;
        /* enable headphone driver and smart low power mode by default */
-       snd_ac97_write(ac97, 0x6a, 0x0050);
-       snd_ac97_write(ac97, 0x6c, 0x0030);
+       snd_ac97_write_cache(ac97, 0x6a, 0x0050);
+       snd_ac97_write_cache(ac97, 0x6c, 0x0030);
        return 0;
 }
similarity index 96%
rename from sound/pci/ac97/ak4531_codec.c
rename to sound/pci/ak4531_codec.c
index c0c1633999eaf60567d0f41752d3528312561e71..33d37b1c42fcc4354919615a43747655fcdafe4b 100644 (file)
 #include <sound/ak4531_codec.h>
 #include <sound/tlv.h>
 
+/*
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Universal routines for AK4531 codec");
 MODULE_LICENSE("GPL");
+*/
 
 #ifdef CONFIG_PROC_FS
 static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531);
@@ -270,7 +272,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0);
 static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0);
 static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0);
 
-static struct snd_kcontrol_new snd_ak4531_controls[] = {
+static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = {
 
 AK4531_DOUBLE_TLV("Master Playback Switch", 0,
                  AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1,
@@ -379,8 +381,9 @@ static u8 snd_ak4531_initial_map[0x19 + 1] = {
        0x01            /* 19: Mic Amp Setup */
 };
 
-int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531,
-                    struct snd_ak4531 **rak4531)
+int __devinit snd_ak4531_mixer(struct snd_card *card,
+                              struct snd_ak4531 *_ak4531,
+                              struct snd_ak4531 **rak4531)
 {
        unsigned int idx;
        int err;
@@ -476,7 +479,8 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry,
                    ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB");
 }
 
-static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531)
+static void __devinit
+snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531)
 {
        struct snd_info_entry *entry;
 
@@ -484,25 +488,3 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453
                snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read);
 }
 #endif
-
-EXPORT_SYMBOL(snd_ak4531_mixer);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL(snd_ak4531_suspend);
-EXPORT_SYMBOL(snd_ak4531_resume);
-#endif
-
-/*
- *  INIT part
- */
-
-static int __init alsa_ak4531_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_ak4531_exit(void)
-{
-}
-
-module_init(alsa_ak4531_init)
-module_exit(alsa_ak4531_exit)
index bc212f41a38a611a84ee679502813377208602e1..e291aa59742e7c31c85e8f220a5248c661916c80 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $
- *
  *  Manuel Jander.
  *
  *  Based on the work of:
index 5f63af6b88a29d35c1c906b6e1e34d88f07780a8..22f18f3cfbc9f45d1b7921aa25ab2399029fe663 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
- *  Copyright (C) 2002, 2005, 2006, 2007 by Andreas Mohr <andi AT lisas.de>
+ *  Copyright (C) 2002, 2005 - 2008 by Andreas Mohr <andi AT lisas.de>
  *
  *  Framework borrowed from Bart Hartgers's als4000.c.
  *  Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
  *  (3 weeks' worth of evenings filled with driver work).
  *  (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros)
  *
+ *  It is quite likely that the AZF3328 chip is the PCI cousin of the
+ *  AZF3318 ("azt1020 pnp", "MM Pro 16") ISA chip, given very similar specs.
+ *
  *  The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name
- *  for compatibility reasons) has the following features:
+ *  for compatibility reasons) from Azfin (joint-venture of Aztech and Fincitec,
+ *  Fincitec acquired by National Semiconductor in 2002, together with the
+ *  Fincitec-related company ARSmikro) has the following features:
  *
+ *  - compatibility & compliance:
+ *    - Microsoft PC 97 ("PC 97 Hardware Design Guide",
+ *                       http://www.microsoft.com/whdc/archive/pcguides.mspx)
+ *    - Microsoft PC 98 Baseline Audio
+ *    - MPU401 UART
+ *    - Sound Blaster Emulation (DOS Box)
  *  - builtin AC97 conformant codec (SNR over 80dB)
  *    Note that "conformant" != "compliant"!! this chip's mixer register layout
  *    *differs* from the standard AC97 layout:
  *    addresses illegally. So far unfortunately it looks like the very flexible
  *    ALSA AC97 support is still not enough to easily compensate for such a
  *    grave layout violation despite all tweaks and quirks mechanisms it offers.
- *  - builtin genuine OPL3
+ *  - builtin genuine OPL3 - verified to work fine, 20080506
  *  - full duplex 16bit playback/record at independent sampling rate
- *  - MPU401 (+ legacy address support) FIXME: how to enable legacy addr??
+ *  - MPU401 (+ legacy address support, claimed by one official spec sheet)
+ *    FIXME: how to enable legacy addr??
  *  - game port (legacy address support)
- *  - builtin 3D enhancement (said to be YAMAHA Ymersion)
  *  - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven
- *    features supported)
+ *    features supported). - See common term "Digital Enhanced Game Port"...
+ *    (probably DirectInput 3.0 spec - confirm)
+ *  - builtin 3D enhancement (said to be YAMAHA Ymersion)
  *  - built-in General DirectX timer having a 20 bits counter
  *    with 1us resolution (see below!)
- *  - I2S serial port for external DAC
+ *  - I2S serial output port for external DAC
  *  - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI
  *  - supports hardware volume control
  *  - single chip low cost solution (128 pin QFP)
  *  - supports programmable Sub-vendor and Sub-system ID
  *    required for Microsoft's logo compliance (FIXME: where?)
+ *    At least the Trident 4D Wave DX has one bit somewhere
+ *    to enable writes to PCI subsystem VID registers, that should be it.
+ *    This might easily be in extended PCI reg space, since PCI168 also has
+ *    some custom data starting at 0x80. What kind of config settings
+ *    are located in our extended PCI space anyway??
  *  - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms
  *
  *  Note that this driver now is actually *better* than the Windows driver,
  *  - "timidity -iAv -B2,8 -Os -EFreverb=0"
  *  - "pmidi -p 128:0 jazz.mid"
  *
+ *  OPL3 hardware playback testing, try something like:
+ *  cat /proc/asound/hwdep
+ *  and
+ *  aconnect -o
+ *  Then use
+ *  sbiload -Dhw:x,y --opl3 /usr/share/sounds/opl3/std.o3 ......./drums.o3
+ *  where x,y is the xx-yy number as given in hwdep.
+ *  Then try
+ *  pmidi -p a:b jazz.mid
+ *  where a:b is the client number plus 0 usually, as given by aconnect above.
+ *  Oh, and make sure to unmute the FM mixer control (doh!)
+ *  NOTE: power use during OPL3 playback is _VERY_ high (70W --> 90W!)
+ *  despite no CPU activity, possibly due to hindering ACPI idling somehow.
+ *  Shouldn't be a problem of the AZF3328 chip itself, I'd hope.
+ *  Higher PCM / FM mixer levels seem to conflict (causes crackling),
+ *  at least sometimes.   Maybe even use with hardware sequencer timer above :)
+ *  adplay/adplug-utils might soon offer hardware-based OPL3 playback, too.
+ *
  *  Certain PCI versions of this card are susceptible to DMA traffic underruns
  *  in some systems (resulting in sound crackling/clicking/popping),
  *  probably because they don't have a DMA FIFO buffer or so.
  *  better than a VIA, yet ironically I still get crackling, like many other
  *  people with the same chipset.
  *  Possible remedies:
+ *  - use speaker (amplifier) output instead of headphone output
+ *    (in case crackling is due to overloaded output clipping)
  *  - plug card into a different PCI slot, preferrably one that isn't shared
  *    too much (this helps a lot, but not completely!)
  *  - get rid of PCI VGA card, use AGP instead
  *  - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX)
  *    Not too helpful.
  *  - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS
- * 
+ *
  * BUGS
- *  - full-duplex might *still* be problematic, not fully tested recently
+ *  - full-duplex might *still* be problematic, however a recent test was fine
  *  - (non-bug) "Bass/Treble or 3D settings don't work" - they do get evaluated
  *    if you set PCM output switch to "pre 3D" instead of "post 3D".
  *    If this can't be set, then get a mixer application that Isn't Stupid (tm)
  *    (e.g. kmix, gamix) - unfortunately several are!!
- * 
+ *  - locking is not entirely clean, especially the audio stream activity
+ *    ints --> may be racy
+ *  - an _unconnected_ secondary joystick at the gameport will be reported
+ *    to be "active" (floating values, not precisely -1) due to the way we need
+ *    to read the Digital Enhanced Game Port. Not sure whether it is fixable.
+ *
  * TODO
  *  - test MPU401 MIDI playback etc.
- *  - add some power micro-management (disable various units of the card
- *    as long as they're unused). However this requires I/O ports which I
+ *  - add more power micro-management (disable various units of the card
+ *    as long as they're unused). However this requires more I/O ports which I
  *    haven't figured out yet and which thus might not even exist...
  *    The standard suspend/resume functionality could probably make use of
  *    some improvement, too...
  *  - figure out some cleverly evil scheme to possibly make ALSA AC97 code
  *    fully accept our quite incompatible ""AC97"" mixer and thus save some
  *    code (but I'm not too optimistic that doing this is possible at all)
+ *  - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport.
  */
 
 #include <asm/io.h>
@@ -138,7 +182,7 @@ MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
 
 #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
+#define SUPPORT_GAMEPORT 1
 #endif
 
 #define DEBUG_MISC     0
@@ -147,13 +191,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
 #define DEBUG_PLAY_REC 0
 #define DEBUG_IO       0
 #define DEBUG_TIMER    0
+#define DEBUG_GAME     0
 #define MIXER_TESTING  0
 
 #if DEBUG_MISC
 #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args)
 #else
 #define snd_azf3328_dbgmisc(format, args...)
-#endif         
+#endif
 
 #if DEBUG_CALLS
 #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args)
@@ -163,25 +208,31 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
 #define snd_azf3328_dbgcalls(format, args...)
 #define snd_azf3328_dbgcallenter()
 #define snd_azf3328_dbgcallleave()
-#endif         
+#endif
 
 #if DEBUG_MIXER
 #define snd_azf3328_dbgmixer(format, args...) printk(format, ##args)
 #else
 #define snd_azf3328_dbgmixer(format, args...)
-#endif         
+#endif
 
 #if DEBUG_PLAY_REC
 #define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args)
 #else
 #define snd_azf3328_dbgplay(format, args...)
-#endif         
+#endif
 
 #if DEBUG_MISC
 #define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args)
 #else
 #define snd_azf3328_dbgtimer(format, args...)
-#endif         
+#endif
+
+#if DEBUG_GAME
+#define snd_azf3328_dbggame(format, args...) printk(KERN_ERR format, ##args)
+#else
+#define snd_azf3328_dbggame(format, args...)
+#endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 module_param_array(index, int, NULL, 0444);
@@ -195,51 +246,62 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;        /* Enable this card *
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard.");
 
-#ifdef SUPPORT_JOYSTICK
-static int joystick[SNDRV_CARDS];
-module_param_array(joystick, bool, NULL, 0444);
-MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard.");
-#endif
-
 static int seqtimer_scaling = 128;
 module_param(seqtimer_scaling, int, 0444);
 MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128.");
 
+struct snd_azf3328_audio_stream {
+       struct snd_pcm_substream *substream;
+       int enabled;
+       int running;
+       unsigned long portbase;
+};
+
+enum snd_azf3328_stream_index {
+  AZF_PLAYBACK = 0,
+  AZF_CAPTURE = 1,
+};
+
 struct snd_azf3328 {
        /* often-used fields towards beginning, then grouped */
-       unsigned long codec_port;
-       unsigned long io2_port;
-       unsigned long mpu_port;
-       unsigned long synth_port;
-       unsigned long mixer_port;
+
+       unsigned long codec_io; /* usually 0xb000, size 128 */
+       unsigned long game_io;  /* usually 0xb400, size 8 */
+       unsigned long mpu_io;   /* usually 0xb800, size 4 */
+       unsigned long opl3_io; /* usually 0xbc00, size 8 */
+       unsigned long mixer_io; /* usually 0xc000, size 64 */
 
        spinlock_t reg_lock;
 
        struct snd_timer *timer;
-       
+
        struct snd_pcm *pcm;
-       struct snd_pcm_substream *playback_substream;
-       struct snd_pcm_substream *capture_substream;
-       unsigned int is_playing;
-       unsigned int is_recording;
+       struct snd_azf3328_audio_stream audio_stream[2];
 
        struct snd_card *card;
        struct snd_rawmidi *rmidi;
 
-#ifdef SUPPORT_JOYSTICK
+#ifdef SUPPORT_GAMEPORT
        struct gameport *gameport;
+       int axes[4];
 #endif
 
        struct pci_dev *pci;
        int irq;
 
+       /* register 0x6a is write-only, thus need to remember setting.
+        * If we need to add more registers here, then we might try to fold this
+        * into some transparent combined shadow register handling with
+        * CONFIG_PM register storage below, but that's slightly difficult. */
+       u16 shadow_reg_codec_6AH;
+
 #ifdef CONFIG_PM
        /* register value containers for power management
         * Note: not always full I/O range preserved (just like Win driver!) */
-       u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2];
-       u16 saved_regs_io2   [AZF_IO_SIZE_IO2_PM / 2];
-       u16 saved_regs_mpu   [AZF_IO_SIZE_MPU_PM / 2];
-       u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2];
+       u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2];
+       u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2];
+       u16 saved_regs_mpu  [AZF_IO_SIZE_MPU_PM / 2];
+       u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2];
        u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2];
 #endif
 };
@@ -252,126 +314,166 @@ static const struct pci_device_id snd_azf3328_ids[] = {
 
 MODULE_DEVICE_TABLE(pci, snd_azf3328_ids);
 
+
+static int
+snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set)
+{
+       u8 prev = inb(reg), new;
+
+       new = (do_set) ? (prev|mask) : (prev & ~mask);
+       /* we need to always write the new value no matter whether it differs
+        * or not, since some register bits don't indicate their setting */
+       outb(new, reg);
+       if (new != prev)
+               return 1;
+
+       return 0;
+}
+
 static inline void
-snd_azf3328_codec_outb(const struct snd_azf3328 *chip, int reg, u8 value)
+snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value)
 {
-       outb(value, chip->codec_port + reg);
+       outb(value, chip->codec_io + reg);
 }
 
 static inline u8
-snd_azf3328_codec_inb(const struct snd_azf3328 *chip, int reg)
+snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg)
 {
-       return inb(chip->codec_port + reg);
+       return inb(chip->codec_io + reg);
 }
 
 static inline void
-snd_azf3328_codec_outw(const struct snd_azf3328 *chip, int reg, u16 value)
+snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
 {
-       outw(value, chip->codec_port + reg);
+       outw(value, chip->codec_io + reg);
 }
 
 static inline u16
-snd_azf3328_codec_inw(const struct snd_azf3328 *chip, int reg)
+snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg)
+{
+       return inw(chip->codec_io + reg);
+}
+
+static inline void
+snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value)
+{
+       outl(value, chip->codec_io + reg);
+}
+
+static inline u32
+snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg)
 {
-       return inw(chip->codec_port + reg);
+       return inl(chip->codec_io + reg);
 }
 
 static inline void
-snd_azf3328_codec_outl(const struct snd_azf3328 *chip, int reg, u32 value)
+snd_azf3328_game_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value)
 {
-       outl(value, chip->codec_port + reg);
+       outb(value, chip->game_io + reg);
 }
 
 static inline void
-snd_azf3328_io2_outb(const struct snd_azf3328 *chip, int reg, u8 value)
+snd_azf3328_game_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
 {
-       outb(value, chip->io2_port + reg);
+       outw(value, chip->game_io + reg);
 }
 
 static inline u8
-snd_azf3328_io2_inb(const struct snd_azf3328 *chip, int reg)
+snd_azf3328_game_inb(const struct snd_azf3328 *chip, unsigned reg)
 {
-       return inb(chip->io2_port + reg);
+       return inb(chip->game_io + reg);
+}
+
+static inline u16
+snd_azf3328_game_inw(const struct snd_azf3328 *chip, unsigned reg)
+{
+       return inw(chip->game_io + reg);
 }
 
 static inline void
-snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, int reg, u16 value)
+snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value)
 {
-       outw(value, chip->mixer_port + reg);
+       outw(value, chip->mixer_io + reg);
 }
 
 static inline u16
-snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, int reg)
+snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg)
 {
-       return inw(chip->mixer_port + reg);
+       return inw(chip->mixer_io + reg);
 }
 
-static void
-snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, int reg, int do_mute)
+#define AZF_MUTE_BIT 0x80
+
+static int
+snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip,
+                          unsigned reg, int do_mute
+)
 {
-       unsigned long portbase = chip->mixer_port + reg + 1;
-       unsigned char oldval;
+       unsigned long portbase = chip->mixer_io + reg + 1;
+       int updated;
 
        /* the mute bit is on the *second* (i.e. right) register of a
         * left/right channel setting */
-       oldval = inb(portbase);
-       if (do_mute)
-               oldval |= 0x80;
-       else
-               oldval &= ~0x80;
-       outb(oldval, portbase);
+       updated = snd_azf3328_io_reg_setb(portbase, AZF_MUTE_BIT, do_mute);
+
+       /* indicate whether it was muted before */
+       return (do_mute) ? !updated : updated;
 }
 
 static void
-snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay)
+snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
+                                        unsigned reg,
+                                        unsigned char dst_vol_left,
+                                        unsigned char dst_vol_right,
+                                        int chan_sel, int delay
+)
 {
-       unsigned long portbase = chip->mixer_port + reg;
+       unsigned long portbase = chip->mixer_io + reg;
        unsigned char curr_vol_left = 0, curr_vol_right = 0;
-       int left_done = 0, right_done = 0;
-       
+       int left_change = 0, right_change = 0;
+
        snd_azf3328_dbgcallenter();
-       if (chan_sel & SET_CHAN_LEFT)
+
+       if (chan_sel & SET_CHAN_LEFT) {
                curr_vol_left  = inb(portbase + 1);
-       else
-               left_done = 1;
-       if (chan_sel & SET_CHAN_RIGHT)
+
+               /* take care of muting flag contained in left channel */
+               if (curr_vol_left & AZF_MUTE_BIT)
+                       dst_vol_left |= AZF_MUTE_BIT;
+               else
+                       dst_vol_left &= ~AZF_MUTE_BIT;
+
+               left_change = (curr_vol_left > dst_vol_left) ? -1 : 1;
+       }
+
+       if (chan_sel & SET_CHAN_RIGHT) {
                curr_vol_right = inb(portbase + 0);
-       else
-               right_done = 1;
-       
-       /* take care of muting flag (0x80) contained in left channel */
-       if (curr_vol_left & 0x80)
-               dst_vol_left |= 0x80;
-       else
-               dst_vol_left &= ~0x80;
+
+               right_change = (curr_vol_right > dst_vol_right) ? -1 : 1;
+       }
 
        do {
-               if (!left_done) {
-                       if (curr_vol_left > dst_vol_left)
-                               curr_vol_left--;
-                       else
-                       if (curr_vol_left < dst_vol_left)
-                               curr_vol_left++;
-                       else
-                           left_done = 1;
-                       outb(curr_vol_left, portbase + 1);
+               if (left_change) {
+                       if (curr_vol_left != dst_vol_left) {
+                               curr_vol_left += left_change;
+                               outb(curr_vol_left, portbase + 1);
+                       } else
+                           left_change = 0;
                }
-               if (!right_done) {
-                       if (curr_vol_right > dst_vol_right)
-                               curr_vol_right--;
-                       else
-                       if (curr_vol_right < dst_vol_right)
-                               curr_vol_right++;
-                       else
-                           right_done = 1;
+               if (right_change) {
+                       if (curr_vol_right != dst_vol_right) {
+                               curr_vol_right += right_change;
+
                        /* during volume change, the right channel is crackling
                         * somewhat more than the left channel, unfortunately.
                         * This seems to be a hardware issue. */
-                       outb(curr_vol_right, portbase + 0);
+                               outb(curr_vol_right, portbase + 0);
+                       } else
+                           right_change = 0;
                }
                if (delay)
                        mdelay(delay);
-       } while ((!left_done) || (!right_done));
+       } while ((left_change) || (right_change));
        snd_azf3328_dbgcallleave();
 }
 
@@ -379,7 +481,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg
  * general mixer element
  */
 struct azf3328_mixer_reg {
-       unsigned int reg;
+       unsigned reg;
        unsigned int lchan_shift, rchan_shift;
        unsigned int mask;
        unsigned int invert: 1;
@@ -544,13 +646,14 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
                "Mix", "Mic"
        };
        static const char * const texts3[] = {
-                "Mic", "CD", "Video", "Aux",
+               "Mic", "CD", "Video", "Aux",
                "Line", "Mix", "Mix Mono", "Phone"
         };
        static const char * const texts4[] = {
                "pre 3D", "post 3D"
         };
        struct azf3328_mixer_reg reg;
+       const char * const *p = NULL;
 
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -561,18 +664,20 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
        if (reg.reg == IDX_MIXER_ADVCTL2) {
                switch(reg.lchan_shift) {
                case 8: /* modem out sel */
-                       strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]);
+                       p = texts1;
                        break;
                case 9: /* mono sel source */
-                       strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]);
+                       p = texts2;
                        break;
                case 15: /* PCM Out Path */
-                       strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]);
+                       p = texts4;
                        break;
                }
        } else
-               strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item]
-);
+       if (reg.reg == IDX_MIXER_REC_SELECT)
+               p = texts3;
+
+       strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]);
         return 0;
 }
 
@@ -583,7 +688,7 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol,
         struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol);
        struct azf3328_mixer_reg reg;
         unsigned short val;
-        
+
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
        val = snd_azf3328_mixer_inw(chip, reg.reg);
        if (reg.reg == IDX_MIXER_REC_SELECT) {
@@ -605,7 +710,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
         struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol);
        struct azf3328_mixer_reg reg;
        unsigned int oreg, nreg, val;
-        
+
        snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
        oreg = snd_azf3328_mixer_inw(chip, reg.reg);
        val = oreg;
@@ -631,9 +736,11 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol,
 static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = {
        AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1),
        AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1),
-       AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1),
-       AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1),
-       AZF3328_MIXER_SWITCH("Wave 3D Bypass Playback Switch", IDX_MIXER_ADVCTL2, 7, 1),
+       AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1),
+       AZF3328_MIXER_VOL_STEREO("PCM Playback Volume",
+                                       IDX_MIXER_WAVEOUT, 0x1f, 1),
+       AZF3328_MIXER_SWITCH("PCM 3D Bypass Playback Switch",
+                                       IDX_MIXER_ADVCTL2, 7, 1),
        AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1),
        AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1),
        AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1),
@@ -717,15 +824,16 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
        snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
 
        /* mute and zero volume channels */
-       for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); idx++) {
+       for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); ++idx) {
                snd_azf3328_mixer_outw(chip,
                        snd_azf3328_init_values[idx][0],
                        snd_azf3328_init_values[idx][1]);
        }
-       
+
        /* add mixer controls */
        sw = snd_azf3328_mixer_controls;
-       for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); idx++, sw++) {
+       for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls);
+                       ++idx, ++sw) {
                if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0)
                        return err;
        }
@@ -757,9 +865,9 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream)
 }
 
 static void
-snd_azf3328_setfmt(struct snd_azf3328 *chip,
-                              unsigned int reg,
-                              unsigned int bitrate,
+snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
+                              unsigned reg,
+                              enum azf_freq_t bitrate,
                               unsigned int format_width,
                               unsigned int channels
 )
@@ -769,24 +877,25 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip,
 
        snd_azf3328_dbgcallenter();
        switch (bitrate) {
-       case  4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
-       case  4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
-       case  5512: val |= SOUNDFORMAT_FREQ_5510; break; /* the AZF3328 names it "5510" for some strange reason */
-       case  6620: val |= SOUNDFORMAT_FREQ_6620; break;
-       case  8000: val |= SOUNDFORMAT_FREQ_8000; break;
-       case  9600: val |= SOUNDFORMAT_FREQ_9600; break;
-       case 11025: val |= SOUNDFORMAT_FREQ_11025; break;
-       case 13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
-       case 16000: val |= SOUNDFORMAT_FREQ_16000; break;
-       case 22050: val |= SOUNDFORMAT_FREQ_22050; break;
-       case 32000: val |= SOUNDFORMAT_FREQ_32000; break;
-       case 44100: val |= SOUNDFORMAT_FREQ_44100; break;
-       case 48000: val |= SOUNDFORMAT_FREQ_48000; break;
-       case 66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
+       case AZF_FREQ_4000:  val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
+       case AZF_FREQ_4800:  val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
+       case AZF_FREQ_5512:
+               /* the AZF3328 names it "5510" for some strange reason */
+                            val |= SOUNDFORMAT_FREQ_5510; break;
+       case AZF_FREQ_6620:  val |= SOUNDFORMAT_FREQ_6620; break;
+       case AZF_FREQ_8000:  val |= SOUNDFORMAT_FREQ_8000; break;
+       case AZF_FREQ_9600:  val |= SOUNDFORMAT_FREQ_9600; break;
+       case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break;
+       case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
+       case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break;
+       case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break;
+       case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break;
        default:
                snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
-               val |= SOUNDFORMAT_FREQ_44100;
-               break;
+               /* fall-through */
+       case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break;
+       case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break;
+       case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
        }
        /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */
        /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */
@@ -805,10 +914,10 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip,
                val |= SOUNDFORMAT_FLAG_16BIT;
 
        spin_lock_irqsave(&chip->reg_lock, flags);
-       
+
        /* set bitrate/format */
        snd_azf3328_codec_outw(chip, reg, val);
-       
+
        /* changing the bitrate/format settings switches off the
         * audio output with an annoying click in case of 8/16bit format change
         * (maybe shutting down DAC/ADC?), thus immediately
@@ -830,31 +939,95 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip,
        snd_azf3328_dbgcallleave();
 }
 
+static inline void
+snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip,
+                           unsigned reg
+)
+{
+       /* choose lowest frequency for low power consumption.
+        * While this will cause louder noise due to rather coarse frequency,
+        * it should never matter since output should always
+        * get disabled properly when idle anyway. */
+       snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1);
+}
+
+static void
+snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip,
+                                       unsigned bitmask,
+                                       int enable
+)
+{
+       if (enable)
+               chip->shadow_reg_codec_6AH &= ~bitmask;
+       else
+               chip->shadow_reg_codec_6AH |= bitmask;
+       snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n",
+                       bitmask, enable, chip->shadow_reg_codec_6AH);
+       snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH);
+}
+
+static inline void
+snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable)
+{
+       snd_azf3328_dbgplay("codec_enable %d\n", enable);
+       /* no idea what exactly is being done here, but I strongly assume it's
+        * PM related */
+       snd_azf3328_codec_reg_6AH_update(
+               chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable
+       );
+}
+
+static void
+snd_azf3328_codec_activity(struct snd_azf3328 *chip,
+                               enum snd_azf3328_stream_index stream_type,
+                               int enable
+)
+{
+       int need_change = (chip->audio_stream[stream_type].running != enable);
+
+       snd_azf3328_dbgplay(
+               "codec_activity: type %d, enable %d, need_change %d\n",
+                               stream_type, enable, need_change
+       );
+       if (need_change) {
+               enum snd_azf3328_stream_index other =
+                       (stream_type == AZF_PLAYBACK) ?
+                               AZF_CAPTURE : AZF_PLAYBACK;
+               /* small check to prevent shutting down the other party
+                * in case it's active */
+               if ((enable) || !(chip->audio_stream[other].running))
+                       snd_azf3328_codec_enable(chip, enable);
+
+               /* ...and adjust clock, too
+                * (reduce noise and power consumption) */
+               if (!enable)
+                       snd_azf3328_codec_setfmt_lowpower(
+                               chip,
+                               chip->audio_stream[stream_type].portbase
+                                       + IDX_IO_PLAY_SOUNDFORMAT
+                       );
+       }
+       chip->audio_stream[stream_type].running = enable;
+}
+
 static void
 snd_azf3328_setdmaa(struct snd_azf3328 *chip,
                                long unsigned int addr,
                                 unsigned int count,
                                 unsigned int size,
-                               int do_recording)
+                               enum snd_azf3328_stream_index stream_type
+)
 {
-       unsigned long flags, portbase;
-       unsigned int is_running;
-
        snd_azf3328_dbgcallenter();
-       if (do_recording) {
-               /* access capture registers, i.e. skip playback reg section */
-               portbase = chip->codec_port + 0x20;
-               is_running = chip->is_recording;
-       } else {
-               /* access the playback register section */
-               portbase = chip->codec_port + 0x00;
-               is_running = chip->is_playing;
-       }
+       if (!chip->audio_stream[stream_type].running) {
+               /* AZF3328 uses a two buffer pointer DMA playback approach */
 
-       /* AZF3328 uses a two buffer pointer DMA playback approach */
-       if (!is_running) {
-               unsigned long addr_area2;
-               unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */
+               unsigned long flags, portbase, addr_area2;
+
+               /* width 32bit (prevent overflow): */
+               unsigned long count_areas, count_tmp;
+
+               portbase = chip->audio_stream[stream_type].portbase;
                count_areas = size/2;
                addr_area2 = addr+count_areas;
                count_areas--; /* max. index */
@@ -884,11 +1057,11 @@ snd_azf3328_playback_prepare(struct snd_pcm_substream *substream)
 
        snd_azf3328_dbgcallenter();
 #if 0
-       snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT,
+       snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT,
                runtime->rate,
                snd_pcm_format_width(runtime->format),
                runtime->channels);
-       snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0);
+       snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK);
 #endif
        snd_azf3328_dbgcallleave();
        return 0;
@@ -906,11 +1079,11 @@ snd_azf3328_capture_prepare(struct snd_pcm_substream *substream)
 
        snd_azf3328_dbgcallenter();
 #if 0
-       snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT,
+       snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT,
                runtime->rate,
                snd_pcm_format_width(runtime->format),
                runtime->channels);
-       snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1);
+       snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE);
 #endif
        snd_azf3328_dbgcallleave();
        return 0;
@@ -923,6 +1096,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_pcm_runtime *runtime = substream->runtime;
        int result = 0;
        unsigned int status1;
+       int previously_muted;
 
        snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd);
 
@@ -930,20 +1104,23 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_START:
                snd_azf3328_dbgplay("START PLAYBACK\n");
 
-               /* mute WaveOut */
-               snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+               /* mute WaveOut (avoid clicking during setup) */
+               previously_muted =
+                       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
 
-               snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT,
+               snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT,
                        runtime->rate,
                        snd_pcm_format_width(runtime->format),
                        runtime->channels);
 
                spin_lock(&chip->reg_lock);
-               /* stop playback */
+               /* first, remember current value: */
                status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS);
+
+               /* stop playback */
                status1 &= ~DMA_RESUME;
                snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
-           
+
                /* FIXME: clear interrupts or what??? */
                snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff);
                spin_unlock(&chip->reg_lock);
@@ -951,7 +1128,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                snd_azf3328_setdmaa(chip, runtime->dma_addr,
                        snd_pcm_lib_period_bytes(substream),
                        snd_pcm_lib_buffer_bytes(substream),
-                       0);
+                       AZF_PLAYBACK);
 
                spin_lock(&chip->reg_lock);
 #ifdef WIN9X
@@ -978,30 +1155,35 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                        DMA_SOMETHING_ELSE);
 #endif
                spin_unlock(&chip->reg_lock);
+               snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1);
 
                /* now unmute WaveOut */
-               snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0);
+               if (!previously_muted)
+                       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0);
 
-               chip->is_playing = 1;
                snd_azf3328_dbgplay("STARTED PLAYBACK\n");
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
                snd_azf3328_dbgplay("RESUME PLAYBACK\n");
                /* resume playback if we were active */
-               if (chip->is_playing)
+               spin_lock(&chip->reg_lock);
+               if (chip->audio_stream[AZF_PLAYBACK].running)
                        snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS,
                                snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME);
+               spin_unlock(&chip->reg_lock);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                snd_azf3328_dbgplay("STOP PLAYBACK\n");
 
-               /* mute WaveOut */
-               snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+               /* mute WaveOut (avoid clicking during setup) */
+               previously_muted =
+                       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
 
                spin_lock(&chip->reg_lock);
-               /* stop playback */
+               /* first, remember current value: */
                status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS);
 
+               /* stop playback */
                status1 &= ~DMA_RESUME;
                snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
 
@@ -1013,10 +1195,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                status1 &= ~DMA_PLAY_SOMETHING1;
                snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1);
                spin_unlock(&chip->reg_lock);
-           
+               snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0);
+
                /* now unmute WaveOut */
-               snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0);
-               chip->is_playing = 0;
+               if (!previously_muted)
+                       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0);
+
                snd_azf3328_dbgplay("STOPPED PLAYBACK\n");
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -1035,7 +1219,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd)
                printk(KERN_ERR "FIXME: unknown trigger mode!\n");
                 return -EINVAL;
        }
-       
+
        snd_azf3328_dbgcallleave();
        return result;
 }
@@ -1057,17 +1241,19 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 
                snd_azf3328_dbgplay("START CAPTURE\n");
 
-               snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT,
+               snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT,
                        runtime->rate,
                        snd_pcm_format_width(runtime->format),
                        runtime->channels);
 
                spin_lock(&chip->reg_lock);
-               /* stop recording */
+               /* first, remember current value: */
                status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS);
+
+               /* stop recording */
                status1 &= ~DMA_RESUME;
                snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
-           
+
                /* FIXME: clear interrupts or what??? */
                snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff);
                spin_unlock(&chip->reg_lock);
@@ -1075,7 +1261,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                snd_azf3328_setdmaa(chip, runtime->dma_addr,
                        snd_pcm_lib_period_bytes(substream),
                        snd_pcm_lib_buffer_bytes(substream),
-                       1);
+                       AZF_CAPTURE);
 
                spin_lock(&chip->reg_lock);
 #ifdef WIN9X
@@ -1102,24 +1288,27 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                        DMA_SOMETHING_ELSE);
 #endif
                spin_unlock(&chip->reg_lock);
+               snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1);
 
-               chip->is_recording = 1;
                snd_azf3328_dbgplay("STARTED CAPTURE\n");
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
                snd_azf3328_dbgplay("RESUME CAPTURE\n");
                /* resume recording if we were active */
-               if (chip->is_recording)
+               spin_lock(&chip->reg_lock);
+               if (chip->audio_stream[AZF_CAPTURE].running)
                        snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS,
                                snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME);
+               spin_unlock(&chip->reg_lock);
                break;
         case SNDRV_PCM_TRIGGER_STOP:
                snd_azf3328_dbgplay("STOP CAPTURE\n");
 
                spin_lock(&chip->reg_lock);
-               /* stop recording */
+               /* first, remember current value: */
                status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS);
 
+               /* stop recording */
                status1 &= ~DMA_RESUME;
                snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
 
@@ -1129,8 +1318,8 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                status1 &= ~DMA_PLAY_SOMETHING1;
                snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1);
                spin_unlock(&chip->reg_lock);
-           
-               chip->is_recording = 0;
+               snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0);
+
                snd_azf3328_dbgplay("STOPPED CAPTURE\n");
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -1149,7 +1338,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd)
                printk(KERN_ERR "FIXME: unknown trigger mode!\n");
                 return -EINVAL;
        }
-       
+
        snd_azf3328_dbgcallleave();
        return result;
 }
@@ -1162,11 +1351,11 @@ snd_azf3328_playback_pointer(struct snd_pcm_substream *substream)
        snd_pcm_uframes_t frmres;
 
 #ifdef QUERY_HARDWARE
-       bufptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_START_1);
+       bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1);
 #else
        bufptr = substream->runtime->dma_addr;
 #endif
-       result = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS);
+       result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS);
 
        /* calculate offset */
        result -= bufptr;
@@ -1183,11 +1372,11 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream)
        snd_pcm_uframes_t frmres;
 
 #ifdef QUERY_HARDWARE
-       bufptr = inl(chip->codec_port+IDX_IO_REC_DMA_START_1);
+       bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1);
 #else
        bufptr = substream->runtime->dma_addr;
 #endif
-       result = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS);
+       result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS);
 
        /* calculate offset */
        result -= bufptr;
@@ -1196,27 +1385,241 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream)
        return frmres;
 }
 
+/******************************************************************/
+
+#ifdef SUPPORT_GAMEPORT
+static inline void
+snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable)
+{
+       snd_azf3328_io_reg_setb(
+               chip->game_io+IDX_GAME_HWCONFIG,
+               GAME_HWCFG_IRQ_ENABLE,
+               enable
+       );
+}
+
+static inline void
+snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable)
+{
+       snd_azf3328_io_reg_setb(
+               chip->game_io+IDX_GAME_HWCONFIG,
+               GAME_HWCFG_LEGACY_ADDRESS_ENABLE,
+               enable
+       );
+}
+
+static inline void
+snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable)
+{
+       snd_azf3328_codec_reg_6AH_update(
+               chip, IO_6A_SOMETHING2_GAMEPORT, enable
+       );
+}
+
+static inline void
+snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
+{
+       /*
+        * skeleton handler only
+        * (we do not want axis reading in interrupt handler - too much load!)
+        */
+       snd_azf3328_dbggame("gameport irq\n");
+
+        /* this should ACK the gameport IRQ properly, hopefully. */
+       snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE);
+}
+
+static int
+snd_azf3328_gameport_open(struct gameport *gameport, int mode)
+{
+       struct snd_azf3328 *chip = gameport_get_port_data(gameport);
+       int res;
+
+       snd_azf3328_dbggame("gameport_open, mode %d\n", mode);
+       switch (mode) {
+       case GAMEPORT_MODE_COOKED:
+       case GAMEPORT_MODE_RAW:
+               res = 0;
+               break;
+       default:
+               res = -1;
+               break;
+       }
+
+       snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0));
+
+       return res;
+}
+
+static void
+snd_azf3328_gameport_close(struct gameport *gameport)
+{
+       struct snd_azf3328 *chip = gameport_get_port_data(gameport);
+
+       snd_azf3328_dbggame("gameport_close\n");
+       snd_azf3328_gameport_axis_circuit_enable(chip, 0);
+}
+
+static int
+snd_azf3328_gameport_cooked_read(struct gameport *gameport,
+                                int *axes,
+                                int *buttons
+)
+{
+       struct snd_azf3328 *chip = gameport_get_port_data(gameport);
+       int i;
+       u8 val;
+       unsigned long flags;
+
+       snd_assert(chip, return 0);
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE);
+       *buttons = (~(val) >> 4) & 0xf;
+
+       /* ok, this one is a bit dirty: cooked_read is being polled by a timer,
+        * thus we're atomic and cannot actively wait in here
+        * (which would be useful for us since it probably would be better
+        * to trigger a measurement in here, then wait a short amount of
+        * time until it's finished, then read values of _this_ measurement).
+        *
+        * Thus we simply resort to reading values if they're available already
+        * and trigger the next measurement.
+        */
+
+       val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG);
+       if (val & GAME_AXES_SAMPLING_READY) {
+               for (i = 0; i < 4; ++i) {
+                       /* configure the axis to read */
+                       val = (i << 4) | 0x0f;
+                       snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val);
+
+                       chip->axes[i] = snd_azf3328_game_inw(
+                                               chip, IDX_GAME_AXIS_VALUE
+                                       );
+               }
+       }
+
+       /* trigger next axes sampling, to be evaluated the next time we
+        * enter this function */
+
+       /* for some very, very strange reason we cannot enable
+        * Measurement Ready monitoring for all axes here,
+        * at least not when only one joystick connected */
+       val = 0x03; /* we're able to monitor axes 1 and 2 only */
+       snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val);
+
+       snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       for (i = 0; i < 4; i++) {
+               axes[i] = chip->axes[i];
+               if (axes[i] == 0xffff)
+                       axes[i] = -1;
+       }
+
+       snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n",
+               axes[0], axes[1], axes[2], axes[3], *buttons
+       );
+
+       return 0;
+}
+
+static int __devinit
+snd_azf3328_gameport(struct snd_azf3328 *chip, int dev)
+{
+       struct gameport *gp;
+
+       chip->gameport = gp = gameport_allocate_port();
+       if (!gp) {
+               printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n");
+               return -ENOMEM;
+       }
+
+       gameport_set_name(gp, "AZF3328 Gameport");
+       gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
+       gameport_set_dev_parent(gp, &chip->pci->dev);
+       gp->io = chip->game_io;
+       gameport_set_port_data(gp, chip);
+
+       gp->open = snd_azf3328_gameport_open;
+       gp->close = snd_azf3328_gameport_close;
+       gp->fuzz = 16; /* seems ok */
+       gp->cooked_read = snd_azf3328_gameport_cooked_read;
+
+       /* DISABLE legacy address: we don't need it! */
+       snd_azf3328_gameport_legacy_address_enable(chip, 0);
+
+       snd_azf3328_gameport_axis_circuit_enable(chip, 0);
+
+       gameport_register_port(chip->gameport);
+
+       return 0;
+}
+
+static void
+snd_azf3328_gameport_free(struct snd_azf3328 *chip)
+{
+       if (chip->gameport) {
+               gameport_unregister_port(chip->gameport);
+               chip->gameport = NULL;
+       }
+       snd_azf3328_gameport_irq_enable(chip, 0);
+}
+#else
+static inline int
+snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) { return -ENOSYS; }
+static inline void
+snd_azf3328_gameport_free(struct snd_azf3328 *chip) { }
+static inline void
+snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip)
+{
+       printk(KERN_WARNING "huh, game port IRQ occurred!?\n");
+}
+#endif /* SUPPORT_GAMEPORT */
+
+/******************************************************************/
+
+static inline void
+snd_azf3328_irq_log_unknown_type(u8 which)
+{
+       snd_azf3328_dbgplay(
+       "azt3328: unknown IRQ type (%x) occurred, please report!\n",
+               which
+       );
+}
+
 static irqreturn_t
 snd_azf3328_interrupt(int irq, void *dev_id)
 {
        struct snd_azf3328 *chip = dev_id;
        u8 status, which;
+#if DEBUG_PLAY_REC
        static unsigned long irq_count;
+#endif
 
        status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS);
 
         /* fast path out, to ease interrupt sharing */
-       if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_TIMER)))
+       if (!(status &
+               (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER)
+       ))
                return IRQ_NONE; /* must be interrupt for another device */
 
-       snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n",
-               irq_count,
-               snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS),
-               snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),
-               status);
-               
+       snd_azf3328_dbgplay(
+               "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, "
+               "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n",
+                       irq_count++ /* debug-only */,
+                       snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS),
+                       snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE),
+                       status
+       );
+
        if (status & IRQ_TIMER) {
-               /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */
+               /* snd_azf3328_dbgplay("timer %ld\n",
+                       snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE)
+                               & TIMER_VALUE_MASK
+               ); */
                if (chip->timer)
                        snd_timer_interrupt(chip->timer, chip->timer->sticks);
                /* ACK timer */
@@ -1232,15 +1635,20 @@ snd_azf3328_interrupt(int irq, void *dev_id)
                snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which);
                        spin_unlock(&chip->reg_lock);
 
-               if (chip->pcm && chip->playback_substream) {
-                       snd_pcm_period_elapsed(chip->playback_substream);
+               if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) {
+                       snd_pcm_period_elapsed(
+                               chip->audio_stream[AZF_PLAYBACK].substream
+                       );
                        snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n",
                                which,
-                               inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS));
+                               snd_azf3328_codec_inl(
+                                       chip, IDX_IO_PLAY_DMA_CURRPOS
+                               )
+                       );
                } else
-                       snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");
+                       printk(KERN_WARNING "azt3328: irq handler problem!\n");
                if (which & IRQ_PLAY_SOMETHING)
-                       snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n");
+                       snd_azf3328_irq_log_unknown_type(which);
        }
        if (status & IRQ_RECORDING) {
                 spin_lock(&chip->reg_lock);
@@ -1249,16 +1657,23 @@ snd_azf3328_interrupt(int irq, void *dev_id)
                snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which);
                spin_unlock(&chip->reg_lock);
 
-               if (chip->pcm && chip->capture_substream) {
-                       snd_pcm_period_elapsed(chip->capture_substream);
+               if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) {
+                       snd_pcm_period_elapsed(
+                               chip->audio_stream[AZF_CAPTURE].substream
+                       );
                        snd_azf3328_dbgplay("REC  period done (#%x), @ %x\n",
                                which,
-                               inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS));
+                               snd_azf3328_codec_inl(
+                                       chip, IDX_IO_REC_DMA_CURRPOS
+                               )
+                       );
                } else
-                       snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n");
+                       printk(KERN_WARNING "azt3328: irq handler problem!\n");
                if (which & IRQ_REC_SOMETHING)
-                       snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n");
+                       snd_azf3328_irq_log_unknown_type(which);
        }
+       if (status & IRQ_GAMEPORT)
+               snd_azf3328_gameport_interrupt(chip);
        /* MPU401 has less critical IRQ requirements
         * than timer and playback/recording, right? */
        if (status & IRQ_MPU401) {
@@ -1268,7 +1683,6 @@ snd_azf3328_interrupt(int irq, void *dev_id)
                 * If so, then I don't know how... */
                snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n");
        }
-       irq_count++;
        return IRQ_HANDLED;
 }
 
@@ -1287,8 +1701,8 @@ static const struct snd_pcm_hardware snd_azf3328_playback =
        .rates =                SNDRV_PCM_RATE_5512 |
                                SNDRV_PCM_RATE_8000_48000 |
                                SNDRV_PCM_RATE_KNOT,
-       .rate_min =             4000,
-       .rate_max =             66200,
+       .rate_min =             AZF_FREQ_4000,
+       .rate_max =             AZF_FREQ_66200,
        .channels_min =         1,
        .channels_max =         2,
        .buffer_bytes_max =     65536,
@@ -1315,8 +1729,8 @@ static const struct snd_pcm_hardware snd_azf3328_capture =
        .rates =                SNDRV_PCM_RATE_5512 |
                                SNDRV_PCM_RATE_8000_48000 |
                                SNDRV_PCM_RATE_KNOT,
-       .rate_min =             4000,
-       .rate_max =             66200,
+       .rate_min =             AZF_FREQ_4000,
+       .rate_max =             AZF_FREQ_66200,
        .channels_min =         1,
        .channels_max =         2,
        .buffer_bytes_max =     65536,
@@ -1329,10 +1743,24 @@ static const struct snd_pcm_hardware snd_azf3328_capture =
 
 
 static unsigned int snd_azf3328_fixed_rates[] = {
-       4000, 4800, 5512, 6620, 8000, 9600, 11025, 13240, 16000, 22050, 32000,
-       44100, 48000, 66200 };
+       AZF_FREQ_4000,
+       AZF_FREQ_4800,
+       AZF_FREQ_5512,
+       AZF_FREQ_6620,
+       AZF_FREQ_8000,
+       AZF_FREQ_9600,
+       AZF_FREQ_11025,
+       AZF_FREQ_13240,
+       AZF_FREQ_16000,
+       AZF_FREQ_22050,
+       AZF_FREQ_32000,
+       AZF_FREQ_44100,
+       AZF_FREQ_48000,
+       AZF_FREQ_66200
+};
+
 static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = {
-       .count = ARRAY_SIZE(snd_azf3328_fixed_rates), 
+       .count = ARRAY_SIZE(snd_azf3328_fixed_rates),
        .list = snd_azf3328_fixed_rates,
        .mask = 0,
 };
@@ -1346,7 +1774,7 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        snd_azf3328_dbgcallenter();
-       chip->playback_substream = substream;
+       chip->audio_stream[AZF_PLAYBACK].substream = substream;
        runtime->hw = snd_azf3328_playback;
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                   &snd_azf3328_hw_constraints_rates);
@@ -1361,7 +1789,7 @@ snd_azf3328_capture_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        snd_azf3328_dbgcallenter();
-       chip->capture_substream = substream;
+       chip->audio_stream[AZF_CAPTURE].substream = substream;
        runtime->hw = snd_azf3328_capture;
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                   &snd_azf3328_hw_constraints_rates);
@@ -1375,7 +1803,7 @@ snd_azf3328_playback_close(struct snd_pcm_substream *substream)
        struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
 
        snd_azf3328_dbgcallenter();
-       chip->playback_substream = NULL;
+       chip->audio_stream[AZF_PLAYBACK].substream = NULL;
        snd_azf3328_dbgcallleave();
        return 0;
 }
@@ -1386,7 +1814,7 @@ snd_azf3328_capture_close(struct snd_pcm_substream *substream)
        struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
 
        snd_azf3328_dbgcallenter();
-       chip->capture_substream = NULL;
+       chip->audio_stream[AZF_CAPTURE].substream = NULL;
        snd_azf3328_dbgcallleave();
        return 0;
 }
@@ -1441,102 +1869,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip, int device)
 
 /******************************************************************/
 
-#ifdef SUPPORT_JOYSTICK
-static int __devinit
-snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev)
-{
-       struct gameport *gp;
-       struct resource *r;
-
-       if (!joystick[dev])
-               return -ENODEV;
-
-       if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) {
-               printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n");
-               return -EBUSY;
-       }
-
-       chip->gameport = gp = gameport_allocate_port();
-       if (!gp) {
-               printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n");
-               release_and_free_resource(r);
-               return -ENOMEM;
-       }
-
-       gameport_set_name(gp, "AZF3328 Gameport");
-       gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));
-       gameport_set_dev_parent(gp, &chip->pci->dev);
-       gp->io = 0x200;
-       gameport_set_port_data(gp, r);
-
-       snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR,
-                             snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY);
-
-       gameport_register_port(chip->gameport);
-
-       return 0;
-}
-
-static void
-snd_azf3328_free_joystick(struct snd_azf3328 *chip)
-{
-       if (chip->gameport) {
-               struct resource *r = gameport_get_port_data(chip->gameport);
-
-               gameport_unregister_port(chip->gameport);
-               chip->gameport = NULL;
-               /* disable gameport */
-               snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR,
-                                     snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
-               release_and_free_resource(r);
-       }
-}
-#else
-static inline int
-snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) { return -ENOSYS; }
-static inline void
-snd_azf3328_free_joystick(struct snd_azf3328 *chip) { }
-#endif
-
-/******************************************************************/
-
-static int
-snd_azf3328_free(struct snd_azf3328 *chip)
-{
-        if (chip->irq < 0)
-                goto __end_hw;
-
-       /* reset (close) mixer */
-       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */
-       snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
-
-        /* interrupt setup - mask everything (FIXME!) */
-       /* well, at least we know how to disable the timer IRQ */
-       snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00);
-
-       if (chip->irq >= 0)
-               synchronize_irq(chip->irq);
-__end_hw:
-       snd_azf3328_free_joystick(chip);
-        if (chip->irq >= 0)
-               free_irq(chip->irq, chip);
-       pci_release_regions(chip->pci);
-       pci_disable_device(chip->pci);
-
-        kfree(chip);
-        return 0;
-}
-
-static int
-snd_azf3328_dev_free(struct snd_device *device)
-{
-       struct snd_azf3328 *chip = device->device_data;
-       return snd_azf3328_free(chip);
-}
-
-/******************************************************************/
-
-/*** NOTE: the physical timer resolution actually is 1024000 ticks per second,
+/*** NOTE: the physical timer resolution actually is 1024000 ticks per second
+ *** (probably derived from main crystal via a divider of 24),
  *** but announcing those attributes to user-space would make programs
  *** configure the timer to a 1 tick value, resulting in an absolutely fatal
  *** timer IRQ storm.
@@ -1564,7 +1898,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
                delay = 49; /* minimum time is 49 ticks */
        }
        snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay);
-       delay |= TIMER_ENABLE_COUNTDOWN | TIMER_ENABLE_IRQ;
+       delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
@@ -1582,7 +1916,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
        chip = snd_timer_chip(timer);
        spin_lock_irqsave(&chip->reg_lock, flags);
        /* disable timer countdown and interrupt */
-       /* FIXME: should we write TIMER_ACK_IRQ here? */
+       /* FIXME: should we write TIMER_IRQ_ACK here? */
        snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        snd_azf3328_dbgcallleave();
@@ -1626,9 +1960,10 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
 
        snd_azf3328_timer_hw.resolution *= seqtimer_scaling;
        snd_azf3328_timer_hw.ticks /= seqtimer_scaling;
-       if ((err = snd_timer_new(chip->card, "AZF3328", &tid, &timer)) < 0) {
+
+       err = snd_timer_new(chip->card, "AZF3328", &tid, &timer);
+       if (err < 0)
                goto out;
-       }
 
        strcpy(timer->name, "AZF3328 timer");
        timer->private_data = chip;
@@ -1636,6 +1971,8 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device)
 
        chip->timer = timer;
 
+       snd_azf3328_timer_stop(timer);
+
        err = 0;
 
 out:
@@ -1645,10 +1982,44 @@ out:
 
 /******************************************************************/
 
+static int
+snd_azf3328_free(struct snd_azf3328 *chip)
+{
+       if (chip->irq < 0)
+               goto __end_hw;
+
+       /* reset (close) mixer:
+        * first mute master volume, then reset
+        */
+       snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
+       snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
+
+       snd_azf3328_timer_stop(chip->timer);
+       snd_azf3328_gameport_free(chip);
+
+       if (chip->irq >= 0)
+               synchronize_irq(chip->irq);
+__end_hw:
+       if (chip->irq >= 0)
+               free_irq(chip->irq, chip);
+       pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
+
+       kfree(chip);
+       return 0;
+}
+
+static int
+snd_azf3328_dev_free(struct snd_device *device)
+{
+       struct snd_azf3328 *chip = device->device_data;
+       return snd_azf3328_free(chip);
+}
+
 #if 0
 /* check whether a bit can be modified */
 static void
-snd_azf3328_test_bit(unsigned int reg, int bit)
+snd_azf3328_test_bit(unsigned unsigned reg, int bit)
 {
        unsigned char val, valoff, valon;
 
@@ -1659,42 +2030,74 @@ snd_azf3328_test_bit(unsigned int reg, int bit)
 
        outb(val|(1 << bit), reg);
        valon = inb(reg);
-       
+
        outb(val, reg);
 
-       printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon);
+       printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n",
+                               reg, bit, val, valoff, valon
+       );
 }
 #endif
 
-#if DEBUG_MISC
-static void
+static inline void
 snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip)
 {
+#if DEBUG_MISC
        u16 tmp;
 
-       snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq);
-
-       snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_inb(chip, 0), snd_azf3328_io2_inb(chip, 1), snd_azf3328_io2_inb(chip, 2), snd_azf3328_io2_inb(chip, 3), snd_azf3328_io2_inb(chip, 4), snd_azf3328_io2_inb(chip, 5));
-
-       for (tmp=0; tmp <= 0x01; tmp += 1)
-               snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp));
+       snd_azf3328_dbgmisc(
+               "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, "
+               "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n",
+               chip->codec_io, chip->game_io, chip->mpu_io,
+               chip->opl3_io, chip->mixer_io, chip->irq
+       );
+
+       snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n",
+               snd_azf3328_game_inb(chip, 0),
+               snd_azf3328_game_inb(chip, 1),
+               snd_azf3328_game_inb(chip, 2),
+               snd_azf3328_game_inb(chip, 3),
+               snd_azf3328_game_inb(chip, 4),
+               snd_azf3328_game_inb(chip, 5)
+       );
+
+       for (tmp = 0; tmp < 0x07; tmp += 1)
+               snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp));
+
+       for (tmp = 0; tmp <= 0x07; tmp += 1)
+               snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n",
+                       tmp, inb(0x200 + tmp), inb(0x208 + tmp));
+
+       for (tmp = 0; tmp <= 0x01; tmp += 1)
+               snd_azf3328_dbgmisc(
+                       "0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, "
+                       "mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n",
+                               tmp,
+                               inb(0x300 + tmp),
+                               inb(0x310 + tmp),
+                               inb(0x320 + tmp),
+                               inb(0x330 + tmp),
+                               inb(0x388 + tmp),
+                               inb(0x38c + tmp)
+               );
 
        for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2)
-               snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", tmp, snd_azf3328_codec_inw(chip, tmp));
+               snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n",
+                       tmp, snd_azf3328_codec_inw(chip, tmp)
+               );
 
        for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2)
-               snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", tmp, snd_azf3328_mixer_inw(chip, tmp));
+               snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n",
+                       tmp, snd_azf3328_mixer_inw(chip, tmp)
+               );
+#endif /* DEBUG_MISC */
 }
-#else
-static inline void
-snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) {}
-#endif
 
 static int __devinit
 snd_azf3328_create(struct snd_card *card,
-                                         struct pci_dev *pci,
-                                         unsigned long device_type,
-                                         struct snd_azf3328 ** rchip)
+                  struct pci_dev *pci,
+                  unsigned long device_type,
+                  struct snd_azf3328 **rchip)
 {
        struct snd_azf3328 *chip;
        int err;
@@ -1705,7 +2108,8 @@ snd_azf3328_create(struct snd_card *card,
 
        *rchip = NULL;
 
-       if ((err = pci_enable_device(pci)) < 0)
+       err = pci_enable_device(pci);
+       if (err < 0)
                return err;
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
@@ -1721,20 +2125,25 @@ snd_azf3328_create(struct snd_card *card,
        /* check if we can restrict PCI DMA transfers to 24 bits */
        if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 ||
            pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n");
+               snd_printk(KERN_ERR "architecture does not support "
+                                       "24bit PCI busmaster DMA\n"
+               );
                err = -ENXIO;
                goto out_err;
        }
 
-       if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) {
+       err = pci_request_regions(pci, "Aztech AZF3328");
+       if (err < 0)
                goto out_err;
-       }
 
-       chip->codec_port = pci_resource_start(pci, 0);
-       chip->io2_port   = pci_resource_start(pci, 1);
-       chip->mpu_port   = pci_resource_start(pci, 2);
-       chip->synth_port = pci_resource_start(pci, 3);
-       chip->mixer_port = pci_resource_start(pci, 4);
+       chip->codec_io = pci_resource_start(pci, 0);
+       chip->game_io  = pci_resource_start(pci, 1);
+       chip->mpu_io   = pci_resource_start(pci, 2);
+       chip->opl3_io = pci_resource_start(pci, 3);
+       chip->mixer_io = pci_resource_start(pci, 4);
+
+       chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00;
+       chip->audio_stream[AZF_CAPTURE].portbase   = chip->codec_io + 0x20;
 
        if (request_irq(pci->irq, snd_azf3328_interrupt,
                        IRQF_SHARED, card->shortname, chip)) {
@@ -1747,29 +2156,29 @@ snd_azf3328_create(struct snd_card *card,
        synchronize_irq(chip->irq);
 
        snd_azf3328_debug_show_ports(chip);
-       
-       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0)
                goto out_err;
-       }
 
        /* create mixer interface & switches */
-       if ((err = snd_azf3328_mixer_new(chip)) < 0)
+       err = snd_azf3328_mixer_new(chip);
+       if (err < 0)
                goto out_err;
 
-#if 0
-       /* set very low bitrate to reduce noise and power consumption? */
-       snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1);
-#endif
+       /* shutdown codecs to save power */
+               /* have snd_azf3328_codec_activity() act properly */
+       chip->audio_stream[AZF_PLAYBACK].running = 1;
+       snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0);
 
        /* standard chip init stuff */
-       /* default IRQ init value */
+               /* default IRQ init value */
        tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE;
 
        spin_lock_irq(&chip->reg_lock);
        snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp);
        snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp);
        snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp);
-       snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); /* disable timer */
        spin_unlock_irq(&chip->reg_lock);
 
        snd_card_set_dev(card, &pci->dev);
@@ -1805,52 +2214,61 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0 );
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
        if (card == NULL)
                return -ENOMEM;
 
        strcpy(card->driver, "AZF3328");
        strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
 
-        if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) {
+       err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip);
+       if (err < 0)
                goto out_err;
-       }
 
        card->private_data = chip;
 
-       if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401,
-                                       chip->mpu_port, MPU401_INFO_INTEGRATED,
-                                       pci->irq, 0, &chip->rmidi)) < 0) {
-               snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port);
+       err = snd_mpu401_uart_new(
+               card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED,
+               pci->irq, 0, &chip->rmidi
+       );
+       if (err < 0) {
+               snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n",
+                               chip->mpu_io
+               );
                goto out_err;
        }
 
-       if ((err = snd_azf3328_timer(chip, 0)) < 0) {
+       err = snd_azf3328_timer(chip, 0);
+       if (err < 0)
                goto out_err;
-       }
 
-       if ((err = snd_azf3328_pcm(chip, 0)) < 0) {
+       err = snd_azf3328_pcm(chip, 0);
+       if (err < 0)
                goto out_err;
-       }
 
-       if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2,
+       if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2,
                            OPL3_HW_AUTO, 1, &opl3) < 0) {
                snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n",
-                          chip->synth_port, chip->synth_port+2 );
+                          chip->opl3_io, chip->opl3_io+2
+               );
        } else {
-               if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+               /* need to use IDs 1, 2 since ID 0 is snd_azf3328_timer above */
+               err = snd_opl3_timer_new(opl3, 1, 2);
+               if (err < 0)
+                       goto out_err;
+               err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+               if (err < 0)
                        goto out_err;
-               }
        }
 
        opl3->private_data = chip;
 
        sprintf(card->longname, "%s at 0x%lx, irq %i",
-               card->shortname, chip->codec_port, chip->irq);
+               card->shortname, chip->codec_io, chip->irq);
 
-       if ((err = snd_card_register(card)) < 0) {
+       err = snd_card_register(card);
+       if (err < 0)
                goto out_err;
-       }
 
 #ifdef MODULE
        printk(
@@ -1861,19 +2279,18 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        1024000 / seqtimer_scaling, seqtimer_scaling);
 #endif
 
-       if (snd_azf3328_config_joystick(chip, dev) < 0)
-               snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR,
-                             snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY);
+       snd_azf3328_gameport(chip, dev);
 
        pci_set_drvdata(pci, card);
        dev++;
 
        err = 0;
        goto out;
-       
+
 out_err:
+       snd_printk(KERN_ERR "azf3328: something failed, exiting\n");
        snd_card_free(card);
-       
+
 out:
        snd_azf3328_dbgcallleave();
        return err;
@@ -1894,27 +2311,31 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct snd_azf3328 *chip = card->private_data;
-       int reg;
+       unsigned reg;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       
+
        snd_pcm_suspend_all(chip->pcm);
 
-       for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
-               chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg)
+               chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2);
 
        /* make sure to disable master volume etc. to prevent looping sound */
        snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
        snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
-       
-       for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
-               chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
-               chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
-               chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
-               chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2);
+
+       for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg)
+               chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2);
+
+       /* manually store the one currently relevant write-only reg, too */
+       chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH;
+
+       for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg)
+               chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg)
+               chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg)
+               chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2);
 
        pci_disable_device(pci);
        pci_save_state(pci);
@@ -1927,7 +2348,7 @@ snd_azf3328_resume(struct pci_dev *pci)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct snd_azf3328 *chip = card->private_data;
-       int reg;
+       unsigned reg;
 
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
@@ -1939,23 +2360,21 @@ snd_azf3328_resume(struct pci_dev *pci)
        }
        pci_set_master(pci);
 
-       for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++)
-               outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++)
-               outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++)
-               outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++)
-               outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2);
-       for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++)
-               outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg)
+               outw(chip->saved_regs_game[reg], chip->game_io + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg)
+               outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg)
+               outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg)
+               outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2);
+       for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg)
+               outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2);
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
-#endif
-
-
+#endif /* CONFIG_PM */
 
 
 static struct pci_driver driver = {
index 679fa992e2bc4db09f5e8a1066e55620295f5e1b..7e3e8942d0733f01fa3b9d5363878f2f9bf2f665 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef __SOUND_AZT3328_H
 #define __SOUND_AZT3328_H
 
-/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 */
+/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10
+ * "WRITE_ONLY"  == register does not indicate actual bit values */
 
 /*** main I/O area port indices ***/
 /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */
   #define SOUNDFORMAT_XTAL1            0x00
   #define SOUNDFORMAT_XTAL2            0x01
     /* all _SUSPECTED_ values are not used by Windows drivers, so we don't
-     * have any hard facts, only rough measurements */
+     * have any hard facts, only rough measurements.
+     * All we know is that the crystal used on the board has 24.576MHz,
+     * like many soundcards (which results in the frequencies below when
+     * using certain divider values selected by the values below) */
     #define SOUNDFORMAT_FREQ_SUSPECTED_4000    0x0c | SOUNDFORMAT_XTAL1
     #define SOUNDFORMAT_FREQ_SUSPECTED_4800    0x0a | SOUNDFORMAT_XTAL1
     #define SOUNDFORMAT_FREQ_5510              0x0c | SOUNDFORMAT_XTAL2
   #define SOUNDFORMAT_FLAG_16BIT       0x0010
   #define SOUNDFORMAT_FLAG_2CHANNELS   0x0020
 
+/* define frequency helpers, for maximum value safety */
+enum azf_freq_t {
+#define AZF_FREQ(rate) AZF_FREQ_##rate = rate
+  AZF_FREQ(4000),
+  AZF_FREQ(4800),
+  AZF_FREQ(5512),
+  AZF_FREQ(6620),
+  AZF_FREQ(8000),
+  AZF_FREQ(9600),
+  AZF_FREQ(11025),
+  AZF_FREQ(13240),
+  AZF_FREQ(16000),
+  AZF_FREQ(22050),
+  AZF_FREQ(32000),
+  AZF_FREQ(44100),
+  AZF_FREQ(48000),
+  AZF_FREQ(66200),
+#undef AZF_FREQ
+} AZF_FREQUENCIES;
+
 /** recording area (see also: playback bit flag definitions) **/
 #define IDX_IO_REC_FLAGS       0x20 /* ??, PU:0x0000 */
 #define IDX_IO_REC_IRQTYPE     0x22 /* ??, PU:0x0000 */
 
 /** DirectX timer, main interrupt area (FIXME: and something else?) **/ 
 #define IDX_IO_TIMER_VALUE     0x60 /* found this timer area by pure luck :-) */
-  #define TIMER_VALUE_MASK             0x000fffffUL /* timer countdown value; triggers IRQ when timer is finished */
-  #define TIMER_ENABLE_COUNTDOWN       0x01000000UL /* activate the timer countdown */
-  #define TIMER_ENABLE_IRQ             0x02000000UL /* trigger timer IRQ on zero transition */
-  #define TIMER_ACK_IRQ                        0x04000000UL /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) had 0x0020 set upon IRQ handler */
+  /* timer countdown value; triggers IRQ when timer is finished */
+  #define TIMER_VALUE_MASK             0x000fffffUL
+  /* activate timer countdown */
+  #define TIMER_COUNTDOWN_ENABLE       0x01000000UL
+  /* trigger timer IRQ on zero transition */
+  #define TIMER_IRQ_ENABLE             0x02000000UL
+  /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?)
+   * had 0x0020 set upon IRQ handler */
+  #define TIMER_IRQ_ACK                        0x04000000UL
 #define IDX_IO_IRQSTATUS        0x64
-  #define IRQ_PLAYBACK                 0x0001
-  #define IRQ_RECORDING                        0x0002
-  #define IRQ_MPU401                   0x0010
-  #define IRQ_TIMER                    0x0020 /* DirectX timer */
-  #define IRQ_UNKNOWN1                 0x0040 /* probably unused, or possibly I2S port? or gameport IRQ? */
-  #define IRQ_UNKNOWN2                 0x0080 /* probably unused, or possibly I2S port? or gameport IRQ? */
+  /* some IRQ bit in here might also be used to signal a power-management timer
+   * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing).
+   * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which
+   * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */
+
+  #define IRQ_PLAYBACK 0x0001
+  #define IRQ_RECORDING        0x0002
+  #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */
+  #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */
+  #define IRQ_MPU401   0x0010
+  #define IRQ_TIMER    0x0020 /* DirectX timer */
+  #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */
+  #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */
 #define IDX_IO_66H             0x66    /* writing 0xffff returns 0x0000 */
-#define IDX_IO_SOME_VALUE      0x68    /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */
-#define IDX_IO_6AH             0x6A    /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */
-  #define IO_6A_PAUSE_PLAYBACK         0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */
-#define IDX_IO_6CH             0x6C
-#define IDX_IO_6EH             0x6E    /* writing 0xffff returns 0x83fe */
-/* further I/O indices not saved/restored, so probably not used */
+  /* this is set to e.g. 0x3ff or 0x300, and writable;
+   * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */
+#define IDX_IO_SOME_VALUE      0x68
+  #define IO_68_RANDOM_TOGGLE1 0x0100  /* toggles randomly */
+  #define IO_68_RANDOM_TOGGLE2 0x0200  /* toggles randomly */
+  /* umm, nope, behaviour of these bits changes depending on what we wrote
+   * to 0x6b!!
+   * And they change upon playback/stop, too:
+   * Writing a value to 0x68 will display this exact value during playback,
+   * too but when stopped it can fall back to a rather different
+   * seemingly random value). Hmm, possibly this is a register which
+   * has a remote shadow which needs proper device supply which only exists
+   * in case playback is active? Or is this driver-induced?
+   */
+
+/* this WORD can be set to have bits 0x0028 activated (FIXME: correct??);
+ * actually inhibits PCM playback!!! maybe power management??: */
+#define IDX_IO_6AH             0x6A /* WRITE_ONLY! */
+  /* bit 5: enabling this will activate permanent counting of bytes 2/3
+   * at gameport I/O (0xb402/3) (equal values each) and cause
+   * gameport legacy I/O at 0x0200 to be _DISABLED_!
+   * Is this Digital Enhanced Game Port Enable??? Or maybe it's Testmode
+   * for Enhanced Digital Gameport (see 4D Wave DX card): */
+  #define IO_6A_SOMETHING1_GAMEPORT    0x0020
+  /* bit 8; sure, this _pauses_ playback (later resumes at same spot!),
+   * but what the heck is this really about??: */
+  #define IO_6A_PAUSE_PLAYBACK_BIT8    0x0100
+  /* bit 9; sure, this _pauses_ playback (later resumes at same spot!),
+   * but what the heck is this really about??: */
+  #define IO_6A_PAUSE_PLAYBACK_BIT9    0x0200
+       /* BIT8 and BIT9 are _NOT_ able to affect OPL3 MIDI playback,
+        * thus it suggests influence on PCM only!!
+        * However OTOH there seems to be no bit anywhere around here
+        * which is able to disable OPL3... */
+  /* bit 10: enabling this actually changes values at legacy gameport
+   * I/O address (0x200); is this enabling of the Digital Enhanced Game Port???
+   * Or maybe this simply switches off the NE558 circuit, since enabling this
+   * still lets us evaluate button states, but not axis states */
+  #define IO_6A_SOMETHING2_GAMEPORT      0x0400
+       /* writing 0x0300: causes quite some crackling during
+        * PC activity such as switching windows (PCI traffic??
+        * --> FIFO/timing settings???) */
+       /* writing 0x0100 plus/or 0x0200 inhibits playback */
+       /* since the Windows .INF file has Flag_Enable_JoyStick and
+        * Flag_Enable_SB_DOS_Emulation directly together, it stands to reason
+        * that some other bit in this same register might be responsible
+        * for SB DOS Emulation activation (note that the file did NOT define
+        * a switch for OPL3!) */
+#define IDX_IO_6CH             0x6C    /* unknown; fully read-writable */
+#define IDX_IO_6EH             0x6E
+       /* writing 0xffff returns 0x83fe (or 0x03fe only).
+        * writing 0x83 (and only 0x83!!) to 0x6f will cause 0x6c to switch
+        * from 0000 to ffff. */
 
+/* further I/O indices not saved/restored and not readable after writing,
+ * so probably not used */
 
-/*** I/O 2 area port indices ***/
+
+/*** Gameport area port indices ***/
 /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ 
-#define AZF_IO_SIZE_IO2                0x08
-#define AZF_IO_SIZE_IO2_PM     0x06
+#define AZF_IO_SIZE_GAME               0x08
+#define AZF_IO_SIZE_GAME_PM    0x06
+
+enum {
+       AZF_GAME_LEGACY_IO_PORT = 0x200
+} AZF_GAME_CONFIGS;
+
+#define IDX_GAME_LEGACY_COMPATIBLE     0x00
+       /* in some operation mode, writing anything to this port
+        * triggers an interrupt:
+        * yup, that's in case IDX_GAME_01H has one of the
+        * axis measurement bits enabled
+        * (and of course one needs to have GAME_HWCFG_IRQ_ENABLE, too) */
+
+#define IDX_GAME_AXES_CONFIG            0x01
+       /* NOTE: layout of this register awfully similar (read: "identical??")
+        * to AD1815JS.pdf (p.29) */
+
+  /* enables axis 1 (X axis) measurement: */
+  #define GAME_AXES_ENABLE_1           0x01
+  /* enables axis 2 (Y axis) measurement: */
+  #define GAME_AXES_ENABLE_2           0x02
+  /* enables axis 3 (X axis) measurement: */
+  #define GAME_AXES_ENABLE_3           0x04
+  /* enables axis 4 (Y axis) measurement: */
+  #define GAME_AXES_ENABLE_4           0x08
+  /* selects the current axis to read the measured value of
+   * (at IDX_GAME_AXIS_VALUE):
+   * 00 = axis 1, 01 = axis 2, 10 = axis 3, 11 = axis 4: */
+  #define GAME_AXES_READ_MASK          0x30
+  /* enable to have the latch continuously accept ADC values
+   * (and continuously cause interrupts in case interrupts are enabled);
+   * AD1815JS.pdf says it's ~16ms interval there: */
+  #define GAME_AXES_LATCH_ENABLE       0x40
+  /* joystick data (measured axes) ready for reading: */
+  #define GAME_AXES_SAMPLING_READY     0x80
+
+  /* NOTE: other card specs (SiS960 and others!) state that the
+   * game position latches should be frozen when reading and be freed
+   * (== reset?) after reading!!!
+   * Freezing most likely means disabling 0x40 (GAME_AXES_LATCH_ENABLE),
+   *  but how to free the value? */
+  /* An internet search for "gameport latch ADC" should provide some insight
+   * into how to program such a gameport system. */
+
+  /* writing 0xf0 to 01H once reset both counters to 0, in some special mode!?
+   * yup, in case 6AH 0x20 is not enabled
+   * (and 0x40 is sufficient, 0xf0 is not needed) */
+
+#define IDX_GAME_AXIS_VALUE    0x02
+       /* R: value of currently configured axis (word value!);
+        * W: trigger axis measurement */
+
+#define IDX_GAME_HWCONFIG      0x04
+       /* note: bits 4 to 7 are never set (== 0) when reading!
+        * --> reserved bits? */
+  /* enables IRQ notification upon axes measurement ready: */
+  #define GAME_HWCFG_IRQ_ENABLE                        0x01
+  /* these bits choose a different frequency for the
+   *  internal ADC counter increment.
+   * hmm, seems to be a combo of bits:
+   * 00 --> standard frequency
+   * 10 --> 1/2
+   * 01 --> 1/20
+   * 11 --> 1/200: */
+  #define GAME_HWCFG_ADC_COUNTER_FREQ_MASK     0x06
 
-#define IDX_IO2_LEGACY_ADDR    0x04
-  #define LEGACY_SOMETHING             0x01 /* OPL3?? */
-  #define LEGACY_JOY                   0x08
+  /* enable gameport legacy I/O address (0x200)
+   * I was unable to locate any configurability for a different address: */
+  #define GAME_HWCFG_LEGACY_ADDRESS_ENABLE     0x08
 
+/*** MPU401 ***/
 #define AZF_IO_SIZE_MPU                0x04
 #define AZF_IO_SIZE_MPU_PM     0x04
 
-#define AZF_IO_SIZE_SYNTH      0x08
-#define AZF_IO_SIZE_SYNTH_PM   0x06
+/*** OPL3 synth ***/
+#define AZF_IO_SIZE_OPL3       0x08
+#define AZF_IO_SIZE_OPL3_PM    0x06
+/* hmm, given that a standard OPL3 has 4 registers only,
+ * there might be some enhanced functionality lurking at the end
+ * (especially since register 0x04 has a "non-empty" value 0xfe) */
 
 /*** mixer I/O area port indices ***/
 /* (only 0x22 of 0x40 bytes saved/restored by Windows driver)
index ecbe79b67e437c0d94018e67e1a15f12984a2dbd..2f8b28add27687cfb63815836a72a06e1050eb92 100644 (file)
@@ -249,6 +249,11 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "MSI K8N Diamond MB [SB0438]",
           .gpio_type = 2,
           .i2c_adc = 1 } ,
+        /* Another MSI K8N Diamond MB, which has apprently a different SSID */
+        { .serial = 0x10091102,
+          .name   = "MSI K8N Diamond MB",
+          .gpio_type = 2,
+          .i2c_adc = 1 } ,
         /* Shuttle XPC SD31P which has an onboard Creative Labs
          * Sound Blaster Live! 24-bit EAX
          * high-definition 7.1 audio processor".
index 548c9cc81af5f5c05967ac2eae2d6c9d5db51ab9..2f283ea6ad9af4cd9762c0a5bb7fc116e4e79798 100644 (file)
@@ -1528,6 +1528,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .ca0151_chip = 1,
         .spk71 = 1,
         .spdif_bug = 1,
+        .invert_shared_spdif = 1,      /* digital/analog switch swapped */
         .adc_1361t = 1,  /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */
         .ac97_chip = 1} ,
        {.vendor = 0x1102, .device = 0x0004, .revision = 0x04,
index fd221209abcb221f6db0dcf323476b8620e40331..f34bbfb705f5f7c870d50012aa17e7c7b57b93ee 100644 (file)
@@ -1578,6 +1578,10 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
                ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
        else
                ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
+       if (emu->card_capabilities->invert_shared_spdif)
+               ucontrol->value.integer.value[0] =
+                       !ucontrol->value.integer.value[0];
+               
        return 0;
 }
 
@@ -1586,15 +1590,18 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
 {
        unsigned long flags;
        struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
-       unsigned int reg, val;
+       unsigned int reg, val, sw;
        int change = 0;
 
+       sw = ucontrol->value.integer.value[0];
+       if (emu->card_capabilities->invert_shared_spdif)
+               sw = !sw;
        spin_lock_irqsave(&emu->reg_lock, flags);
        if ( emu->card_capabilities->i2c_adc) {
                /* Do nothing for Audigy 2 ZS Notebook */
        } else if (emu->audigy) {
                reg = inl(emu->port + A_IOCFG);
-               val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
+               val = sw ? A_IOCFG_GPOUT0 : 0;
                change = (reg & A_IOCFG_GPOUT0) != val;
                if (change) {
                        reg &= ~A_IOCFG_GPOUT0;
@@ -1603,7 +1610,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
                }
        }
        reg = inl(emu->port + HCFG);
-       val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
+       val = sw ? HCFG_GPOUT0 : 0;
        change |= (reg & HCFG_GPOUT0) != val;
        if (change) {
                reg &= ~HCFG_GPOUT0;
index 916c1dbcd53cf919f6a420b86f893a676115302e..7d379f5131fbf61d4ab527a51bac881592c96fff 100644 (file)
@@ -437,43 +437,49 @@ static void get_single_page_range(struct snd_util_memhdr *hdr,
        *last_page_ret = last_page;
 }
 
+/* release allocated pages */
+static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page,
+                              int last_page)
+{
+       int page;
+
+       for (page = first_page; page <= last_page; page++) {
+               free_page((unsigned long)emu->page_ptr_table[page]);
+               emu->page_addr_table[page] = 0;
+               emu->page_ptr_table[page] = NULL;
+       }
+}
+
 /*
  * allocate kernel pages
  */
 static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
 {
        int page, first_page, last_page;
-       struct snd_dma_buffer dmab;
 
        emu10k1_memblk_init(blk);
        get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
        /* allocate kernel pages */
        for (page = first_page; page <= last_page; page++) {
-               if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
-                                       PAGE_SIZE, &dmab) < 0)
-                       goto __fail;
-               if (! is_valid_page(emu, dmab.addr)) {
-                       snd_dma_free_pages(&dmab);
-                       goto __fail;
+               /* first try to allocate from <4GB zone */
+               struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 |
+                                           __GFP_NOWARN);
+               if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) {
+                       if (p)
+                               __free_page(p);
+                       /* try to allocate from <16MB zone */
+                       p = alloc_page(GFP_ATOMIC | GFP_DMA |
+                                      __GFP_NORETRY | /* no OOM-killer */
+                                      __GFP_NOWARN);
+               }
+               if (!p) {
+                       __synth_free_pages(emu, first_page, page - 1);
+                       return -ENOMEM;
                }
-               emu->page_addr_table[page] = dmab.addr;
-               emu->page_ptr_table[page] = dmab.area;
+               emu->page_addr_table[page] = page_to_phys(p);
+               emu->page_ptr_table[page] = page_address(p);
        }
        return 0;
-
-__fail:
-       /* release allocated pages */
-       last_page = page - 1;
-       for (page = first_page; page <= last_page; page++) {
-               dmab.area = emu->page_ptr_table[page];
-               dmab.addr = emu->page_addr_table[page];
-               dmab.bytes = PAGE_SIZE;
-               snd_dma_free_pages(&dmab);
-               emu->page_addr_table[page] = 0;
-               emu->page_ptr_table[page] = NULL;
-       }
-
-       return -ENOMEM;
 }
 
 /*
@@ -481,23 +487,10 @@ __fail:
  */
 static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk)
 {
-       int page, first_page, last_page;
-       struct snd_dma_buffer dmab;
+       int first_page, last_page;
 
        get_single_page_range(emu->memhdr, blk, &first_page, &last_page);
-       dmab.dev.type = SNDRV_DMA_TYPE_DEV;
-       dmab.dev.dev = snd_dma_pci_data(emu->pci);
-       for (page = first_page; page <= last_page; page++) {
-               if (emu->page_ptr_table[page] == NULL)
-                       continue;
-               dmab.area = emu->page_ptr_table[page];
-               dmab.addr = emu->page_addr_table[page];
-               dmab.bytes = PAGE_SIZE;
-               snd_dma_free_pages(&dmab);
-               emu->page_addr_table[page] = 0;
-               emu->page_ptr_table[page] = NULL;
-       }
-
+       __synth_free_pages(emu, first_page, last_page);
        return 0;
 }
 
index a6be6e3e8716026b8a8e129f5e7bc9d9ec31b37f..d2e1093f8e972306727255a46ffb7ce7d59ccf2e 100644 (file)
@@ -2335,7 +2335,7 @@ int snd_hda_check_board_config(struct hda_codec *codec,
        if (!tbl)
                return -1;
        if (tbl->value >= 0 && tbl->value < num_configs) {
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
                char tmp[10];
                const char *model = NULL;
                if (models)
index dcd390b2bbaad8b031c8a7fc49ca5aa91f0b6356..efc682888b3173242510a0705accba40b09ad1cd 100644 (file)
@@ -78,7 +78,7 @@ enum {
 #define AC_VERB_GET_BEEP_CONTROL               0x0f0a
 #define AC_VERB_GET_EAPD_BTLENABLE             0x0f0c
 #define AC_VERB_GET_DIGI_CONVERT_1             0x0f0d
-#define AC_VERB_GET_DIGI_CONVERT_2             0x0f0e
+#define AC_VERB_GET_DIGI_CONVERT_2             0x0f0e /* unused */
 #define AC_VERB_GET_VOLUME_KNOB_CONTROL                0x0f0f
 /* f10-f1a: GPIO */
 #define AC_VERB_GET_GPIO_DATA                  0x0f15
index 2177d9af533496a4583d943c6f648d241f9ef078..6e18a422d993efcf68a2bf4be92d534f96f30d25 100644 (file)
@@ -88,7 +88,7 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
 
 static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
 {
-#ifndef CONFIG_SND_DEBUG_DETECT
+#ifndef CONFIG_SND_DEBUG_VERBOSE
        if (!capable(CAP_SYS_RAWIO))
                return -EACCES;
 #endif
index b3a618eb42cdf5b4a45bc861312b974b7ce00581..16715a68ba5e59c362b5ea3d3db252b4f022523d 100644 (file)
@@ -55,6 +55,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static char *model[SNDRV_CARDS];
 static int position_fix[SNDRV_CARDS];
+static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int single_cmd;
 static int enable_msi;
@@ -69,7 +70,9 @@ module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
-                "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
+                "(0 = auto, 1 = none, 2 = POSBUF).");
+module_param_array(bdl_pos_adj, int, NULL, 0644);
+MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 module_param(single_cmd, bool, 0444);
@@ -197,6 +200,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define ATIHDMI_NUM_CAPTURE    0
 #define ATIHDMI_NUM_PLAYBACK   1
 
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE       3
+#define TERA_NUM_PLAYBACK      4
+
 /* this number is statically defined for simplicity */
 #define MAX_AZX_DEV            16
 
@@ -259,9 +266,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 /* position fix mode */
 enum {
        POS_FIX_AUTO,
-       POS_FIX_NONE,
+       POS_FIX_LPIB,
        POS_FIX_POSBUF,
-       POS_FIX_FIFO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -285,6 +291,7 @@ struct azx_dev {
        u32 *posbuf;            /* position buffer pointer */
 
        unsigned int bufsize;   /* size of the play buffer in bytes */
+       unsigned int period_bytes; /* size of the period in bytes */
        unsigned int frags;     /* number for period in the play buffer */
        unsigned int fifo_size; /* FIFO size */
 
@@ -301,11 +308,11 @@ struct azx_dev {
                                         */
        unsigned char stream_tag;       /* assigned stream */
        unsigned char index;            /* stream index */
-       /* for sanity check of position buffer */
-       unsigned int period_intr;
 
        unsigned int opened :1;
        unsigned int running :1;
+       unsigned int irq_pending :1;
+       unsigned int irq_ignore :1;
 };
 
 /* CORB/RIRB */
@@ -323,6 +330,7 @@ struct azx_rb {
 struct azx {
        struct snd_card *card;
        struct pci_dev *pci;
+       int dev_index;
 
        /* chip type specific */
        int driver_type;
@@ -366,9 +374,13 @@ struct azx {
        unsigned int single_cmd :1;
        unsigned int polling_mode :1;
        unsigned int msi :1;
+       unsigned int irq_pending_warned :1;
 
        /* for debugging */
        unsigned int last_cmd;  /* last issued command (to sync) */
+
+       /* for pending irqs */
+       struct work_struct irq_pending_work;
 };
 
 /* driver types */
@@ -381,6 +393,7 @@ enum {
        AZX_DRIVER_SIS,
        AZX_DRIVER_ULI,
        AZX_DRIVER_NVIDIA,
+       AZX_DRIVER_TERA,
 };
 
 static char *driver_short_names[] __devinitdata = {
@@ -392,6 +405,7 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_SIS] = "HDA SIS966",
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
        [AZX_DRIVER_NVIDIA] = "HDA NVidia",
+       [AZX_DRIVER_TERA] = "HDA Teradici", 
 };
 
 /*
@@ -426,11 +440,6 @@ static char *driver_short_names[] __devinitdata = {
 /* for pcm support */
 #define get_azx_dev(substream) (substream->runtime->private_data)
 
-/* Get the upper 32bit of the given dma_addr_t
- * Compiler should optimize and eliminate the code if dma_addr_t is 32bit
- */
-#define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0)
-
 static int azx_acquire_irq(struct azx *chip, int do_disconnect);
 
 /*
@@ -461,7 +470,7 @@ static void azx_init_cmd_io(struct azx *chip)
        chip->corb.addr = chip->rb.addr;
        chip->corb.buf = (u32 *)chip->rb.area;
        azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
-       azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
+       azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr));
 
        /* set the corb size to 256 entries (ULI requires explicitly) */
        azx_writeb(chip, CORBSIZE, 0x02);
@@ -476,7 +485,7 @@ static void azx_init_cmd_io(struct azx *chip)
        chip->rirb.addr = chip->rb.addr + 2048;
        chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
        azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
-       azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
+       azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr));
 
        /* set the rirb size to 256 entries (ULI requires explicitly) */
        azx_writeb(chip, RIRBSIZE, 0x02);
@@ -847,7 +856,7 @@ static void azx_init_chip(struct azx *chip)
 
        /* program the position buffer */
        azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
-       azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr));
+       azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr));
 
        chip->initialized = 1;
 }
@@ -908,6 +917,8 @@ static void azx_init_pci(struct azx *chip)
 }
 
 
+static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
+
 /*
  * interrupt handler
  */
@@ -930,11 +941,23 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
                azx_dev = &chip->azx_dev[i];
                if (status & azx_dev->sd_int_sta_mask) {
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
-                       if (azx_dev->substream && azx_dev->running) {
-                               azx_dev->period_intr++;
+                       if (!azx_dev->substream || !azx_dev->running)
+                               continue;
+                       /* ignore the first dummy IRQ (due to pos_adj) */
+                       if (azx_dev->irq_ignore) {
+                               azx_dev->irq_ignore = 0;
+                               continue;
+                       }
+                       /* check whether this IRQ is really acceptable */
+                       if (azx_position_ok(chip, azx_dev)) {
+                               azx_dev->irq_pending = 0;
                                spin_unlock(&chip->reg_lock);
                                snd_pcm_period_elapsed(azx_dev->substream);
                                spin_lock(&chip->reg_lock);
+                       } else {
+                               /* bogus IRQ, process it later */
+                               azx_dev->irq_pending = 1;
+                               schedule_work(&chip->irq_pending_work);
                        }
                }
        }
@@ -958,60 +981,108 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 }
 
 
+/*
+ * set up a BDL entry
+ */
+static int setup_bdle(struct snd_pcm_substream *substream,
+                     struct azx_dev *azx_dev, u32 **bdlp,
+                     int ofs, int size, int with_ioc)
+{
+       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+       u32 *bdl = *bdlp;
+
+       while (size > 0) {
+               dma_addr_t addr;
+               int chunk;
+
+               if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
+                       return -EINVAL;
+
+               addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+               /* program the address field of the BDL entry */
+               bdl[0] = cpu_to_le32((u32)addr);
+               bdl[1] = cpu_to_le32(upper_32_bits(addr));
+               /* program the size field of the BDL entry */
+               chunk = PAGE_SIZE - (ofs % PAGE_SIZE);
+               if (size < chunk)
+                       chunk = size;
+               bdl[2] = cpu_to_le32(chunk);
+               /* program the IOC to enable interrupt
+                * only when the whole fragment is processed
+                */
+               size -= chunk;
+               bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
+               bdl += 4;
+               azx_dev->frags++;
+               ofs += chunk;
+       }
+       *bdlp = bdl;
+       return ofs;
+}
+
 /*
  * set up BDL entries
  */
-static int azx_setup_periods(struct snd_pcm_substream *substream,
+static int azx_setup_periods(struct azx *chip,
+                            struct snd_pcm_substream *substream,
                             struct azx_dev *azx_dev)
 {
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
        u32 *bdl;
        int i, ofs, periods, period_bytes;
+       int pos_adj;
 
        /* reset BDL address */
        azx_sd_writel(azx_dev, SD_BDLPL, 0);
        azx_sd_writel(azx_dev, SD_BDLPU, 0);
 
        period_bytes = snd_pcm_lib_period_bytes(substream);
+       azx_dev->period_bytes = period_bytes;
        periods = azx_dev->bufsize / period_bytes;
 
        /* program the initial BDL entries */
        bdl = (u32 *)azx_dev->bdl.area;
        ofs = 0;
        azx_dev->frags = 0;
-       for (i = 0; i < periods; i++) {
-               int size, rest;
-               if (i >= AZX_MAX_BDL_ENTRIES) {
-                       snd_printk(KERN_ERR "Too many BDL entries: "
-                                  "buffer=%d, period=%d\n",
-                                  azx_dev->bufsize, period_bytes);
-                       /* reset */
-                       azx_sd_writel(azx_dev, SD_BDLPL, 0);
-                       azx_sd_writel(azx_dev, SD_BDLPU, 0);
-                       return -EINVAL;
+       azx_dev->irq_ignore = 0;
+       pos_adj = bdl_pos_adj[chip->dev_index];
+       if (pos_adj > 0) {
+               struct snd_pcm_runtime *runtime = substream->runtime;
+               pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
+               if (!pos_adj)
+                       pos_adj = 1;
+               pos_adj = frames_to_bytes(runtime, pos_adj);
+               if (pos_adj >= period_bytes) {
+                       snd_printk(KERN_WARNING "Too big adjustment %d\n",
+                                  bdl_pos_adj[chip->dev_index]);
+                       pos_adj = 0;
+               } else {
+                       ofs = setup_bdle(substream, azx_dev,
+                                        &bdl, ofs, pos_adj, 1);
+                       if (ofs < 0)
+                               goto error;
+                       azx_dev->irq_ignore = 1;
                }
-               rest = period_bytes;
-               do {
-                       dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
-                       /* program the address field of the BDL entry */
-                       bdl[0] = cpu_to_le32((u32)addr);
-                       bdl[1] = cpu_to_le32(upper_32bit(addr));
-                       /* program the size field of the BDL entry */
-                       size = PAGE_SIZE - (ofs % PAGE_SIZE);
-                       if (rest < size)
-                               size = rest;
-                       bdl[2] = cpu_to_le32(size);
-                       /* program the IOC to enable interrupt
-                        * only when the whole fragment is processed
-                        */
-                       rest -= size;
-                       bdl[3] = rest ? 0 : cpu_to_le32(0x01);
-                       bdl += 4;
-                       azx_dev->frags++;
-                       ofs += size;
-               } while (rest > 0);
+       } else
+               pos_adj = 0;
+       for (i = 0; i < periods; i++) {
+               if (i == periods - 1 && pos_adj)
+                       ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+                                        period_bytes - pos_adj, 0);
+               else
+                       ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+                                        period_bytes, 1);
+               if (ofs < 0)
+                       goto error;
        }
        return 0;
+
+ error:
+       snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
+                  azx_dev->bufsize, period_bytes);
+       /* reset */
+       azx_sd_writel(azx_dev, SD_BDLPL, 0);
+       azx_sd_writel(azx_dev, SD_BDLPU, 0);
+       return -EINVAL;
 }
 
 /*
@@ -1062,7 +1133,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        /* lower BDL address */
        azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
        /* upper BDL address */
-       azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr));
+       azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 
        /* enable the position buffer */
        if (chip->position_fix == POS_FIX_POSBUF ||
@@ -1085,7 +1156,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
  */
 
 static unsigned int azx_max_codecs[] __devinitdata = {
-       [AZX_DRIVER_ICH] = 3,
+       [AZX_DRIVER_ICH] = 4,           /* Some ICH9 boards use SD3 */
        [AZX_DRIVER_SCH] = 3,
        [AZX_DRIVER_ATI] = 4,
        [AZX_DRIVER_ATIHDMI] = 4,
@@ -1093,6 +1164,7 @@ static unsigned int azx_max_codecs[] __devinitdata = {
        [AZX_DRIVER_SIS] = 3,           /* FIXME: correct? */
        [AZX_DRIVER_ULI] = 3,           /* FIXME: correct? */
        [AZX_DRIVER_NVIDIA] = 3,        /* FIXME: correct? */
+       [AZX_DRIVER_TERA] = 1,
 };
 
 static int __devinit azx_codec_create(struct azx *chip, const char *model,
@@ -1316,7 +1388,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 
        snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
                    azx_dev->bufsize, azx_dev->format_val);
-       if (azx_setup_periods(substream, azx_dev) < 0)
+       if (azx_setup_periods(chip, substream, azx_dev) < 0)
                return -EINVAL;
        azx_setup_controller(chip, azx_dev);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1421,35 +1493,113 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        return 0;
 }
 
-static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+static unsigned int azx_get_position(struct azx *chip,
+                                    struct azx_dev *azx_dev)
 {
-       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
-       struct azx *chip = apcm->chip;
-       struct azx_dev *azx_dev = get_azx_dev(substream);
        unsigned int pos;
 
        if (chip->position_fix == POS_FIX_POSBUF ||
            chip->position_fix == POS_FIX_AUTO) {
                /* use the position buffer */
                pos = le32_to_cpu(*azx_dev->posbuf);
-               if (chip->position_fix == POS_FIX_AUTO &&
-                   azx_dev->period_intr == 1 && !pos) {
-                       printk(KERN_WARNING
-                              "hda-intel: Invalid position buffer, "
-                              "using LPIB read method instead.\n");
-                       chip->position_fix = POS_FIX_NONE;
-                       goto read_lpib;
-               }
        } else {
-       read_lpib:
                /* read LPIB */
                pos = azx_sd_readl(azx_dev, SD_LPIB);
-               if (chip->position_fix == POS_FIX_FIFO)
-                       pos += azx_dev->fifo_size;
        }
        if (pos >= azx_dev->bufsize)
                pos = 0;
-       return bytes_to_frames(substream->runtime, pos);
+       return pos;
+}
+
+static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
+       struct azx *chip = apcm->chip;
+       struct azx_dev *azx_dev = get_azx_dev(substream);
+       return bytes_to_frames(substream->runtime,
+                              azx_get_position(chip, azx_dev));
+}
+
+/*
+ * Check whether the current DMA position is acceptable for updating
+ * periods.  Returns non-zero if it's OK.
+ *
+ * Many HD-audio controllers appear pretty inaccurate about
+ * the update-IRQ timing.  The IRQ is issued before actually the
+ * data is processed.  So, we need to process it afterwords in a
+ * workqueue.
+ */
+static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
+{
+       unsigned int pos;
+
+       pos = azx_get_position(chip, azx_dev);
+       if (chip->position_fix == POS_FIX_AUTO) {
+               if (!pos) {
+                       printk(KERN_WARNING
+                              "hda-intel: Invalid position buffer, "
+                              "using LPIB read method instead.\n");
+                       chip->position_fix = POS_FIX_LPIB;
+                       pos = azx_get_position(chip, azx_dev);
+               } else
+                       chip->position_fix = POS_FIX_POSBUF;
+       }
+
+       if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
+               return 0; /* NG - it's below the period boundary */
+       return 1; /* OK, it's fine */
+}
+
+/*
+ * The work for pending PCM period updates.
+ */
+static void azx_irq_pending_work(struct work_struct *work)
+{
+       struct azx *chip = container_of(work, struct azx, irq_pending_work);
+       int i, pending;
+
+       if (!chip->irq_pending_warned) {
+               printk(KERN_WARNING
+                      "hda-intel: IRQ timing workaround is activated "
+                      "for card #%d. Suggest a bigger bdl_pos_adj.\n",
+                      chip->card->number);
+               chip->irq_pending_warned = 1;
+       }
+
+       for (;;) {
+               pending = 0;
+               spin_lock_irq(&chip->reg_lock);
+               for (i = 0; i < chip->num_streams; i++) {
+                       struct azx_dev *azx_dev = &chip->azx_dev[i];
+                       if (!azx_dev->irq_pending ||
+                           !azx_dev->substream ||
+                           !azx_dev->running)
+                               continue;
+                       if (azx_position_ok(chip, azx_dev)) {
+                               azx_dev->irq_pending = 0;
+                               spin_unlock(&chip->reg_lock);
+                               snd_pcm_period_elapsed(azx_dev->substream);
+                               spin_lock(&chip->reg_lock);
+                       } else
+                               pending++;
+               }
+               spin_unlock_irq(&chip->reg_lock);
+               if (!pending)
+                       return;
+               cond_resched();
+       }
+}
+
+/* clear irq_pending flags and assure no on-going workq */
+static void azx_clear_irq_pending(struct azx *chip)
+{
+       int i;
+
+       spin_lock_irq(&chip->reg_lock);
+       for (i = 0; i < chip->num_streams; i++)
+               chip->azx_dev[i].irq_pending = 0;
+       spin_unlock_irq(&chip->reg_lock);
+       flush_scheduled_work();
 }
 
 static struct snd_pcm_ops azx_pcm_ops = {
@@ -1676,6 +1826,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
        int i;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       azx_clear_irq_pending(chip);
        for (i = 0; i < AZX_MAX_PCMS; i++)
                snd_pcm_suspend_all(chip->pcm[i]);
        if (chip->initialized)
@@ -1732,6 +1883,7 @@ static int azx_free(struct azx *chip)
        int i;
 
        if (chip->initialized) {
+               azx_clear_irq_pending(chip);
                for (i = 0; i < chip->num_streams; i++)
                        azx_stream_stop(chip, &chip->azx_dev[i]);
                azx_stop_chip(chip);
@@ -1770,9 +1922,9 @@ static int azx_dev_free(struct snd_device *device)
  * white/black-listing for position_fix
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
-       SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE),
-       SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE),
-       SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE),
+       SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        {}
 };
 
@@ -1857,12 +2009,25 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->irq = -1;
        chip->driver_type = driver_type;
        chip->msi = enable_msi;
+       chip->dev_index = dev;
+       INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
 
        chip->position_fix = check_position_fix(chip, position_fix[dev]);
        check_probe_mask(chip, dev);
 
        chip->single_cmd = single_cmd;
 
+       if (bdl_pos_adj[dev] < 0) {
+               switch (chip->driver_type) {
+               case AZX_DRIVER_ICH:
+                       bdl_pos_adj[dev] = 1;
+                       break;
+               default:
+                       bdl_pos_adj[dev] = 32;
+                       break;
+               }
+       }
+
 #if BITS_PER_LONG != 64
        /* Fix up base address on ULI M5461 */
        if (chip->driver_type == AZX_DRIVER_ULI) {
@@ -2089,6 +2254,7 @@ static struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
        { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
        { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
+       { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
        { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
        { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
        { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
@@ -2141,6 +2307,8 @@ static struct pci_device_id azx_ids[] = {
        { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA },
        { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA },
        { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA },
+       /* Teradici */
+       { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index 5633f77f8f3b74885f36ff33dec5481771096871..1e5aff5c48d16910074503907775e6d17eac5d66 100644 (file)
@@ -366,8 +366,6 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
 {
        unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
                                                AC_VERB_GET_DIGI_CONVERT_1, 0);
-       unsigned int digi2 = snd_hda_codec_read(codec, nid, 0,
-                                               AC_VERB_GET_DIGI_CONVERT_2, 0);
        snd_iprintf(buffer, "  Digital:");
        if (digi1 & AC_DIG1_ENABLE)
                snd_iprintf(buffer, " Enabled");
@@ -386,7 +384,8 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
        if (digi1 & AC_DIG1_LEVEL)
                snd_iprintf(buffer, " GenLevel");
        snd_iprintf(buffer, "\n");
-       snd_iprintf(buffer, "  Digital category: 0x%x\n", digi2 & AC_DIG2_CC);
+       snd_iprintf(buffer, "  Digital category: 0x%x\n",
+                   (digi1 >> 8) & AC_DIG2_CC);
 }
 
 static const char *get_pwr_state(u32 state)
index a99e86d742782ae14d2123c87696f8428bebd54c..e8003d99f0bfe3bb071d761a9a84922dd7d8bd07 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
-#include <linux/mutex.h>
 
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -64,7 +63,6 @@ struct ad198x_spec {
        /* PCM information */
        struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
-       struct mutex amp_mutex; /* PCM volume/mute control mutex */
        unsigned int spdif_route;
 
        /* dynamic controls, init_verbs and input_mux */
@@ -1618,6 +1616,7 @@ static const char *ad1981_models[AD1981_MODELS] = {
 
 static struct snd_pci_quirk ad1981_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
+       SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
        /* All HP models */
        SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
        SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
@@ -2623,7 +2622,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 {
        struct ad198x_spec *spec = codec->spec;
        hda_nid_t nid;
-       int idx, err;
+       int i, idx, err;
        char name[32];
 
        if (! pin)
@@ -2631,16 +2630,26 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 
        idx = ad1988_pin_idx(pin);
        nid = ad1988_idx_to_dac(codec, idx);
-       /* specify the DAC as the extra output */
-       if (! spec->multiout.hp_nid)
-               spec->multiout.hp_nid = nid;
-       else
-               spec->multiout.extra_out_nid[0] = nid;
-       /* control HP volume/switch on the output mixer amp */
-       sprintf(name, "%s Playback Volume", pfx);
-       if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
-                              HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
-               return err;
+       /* check whether the corresponding DAC was already taken */
+       for (i = 0; i < spec->autocfg.line_outs; i++) {
+               hda_nid_t pin = spec->autocfg.line_out_pins[i];
+               hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
+               if (dac == nid)
+                       break;
+       }
+       if (i >= spec->autocfg.line_outs) {
+               /* specify the DAC as the extra output */
+               if (!spec->multiout.hp_nid)
+                       spec->multiout.hp_nid = nid;
+               else
+                       spec->multiout.extra_out_nid[0] = nid;
+               /* control HP volume/switch on the output mixer amp */
+               sprintf(name, "%s Playback Volume", pfx);
+               err = add_control(spec, AD_CTL_WIDGET_VOL, name,
+                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+       }
        nid = ad1988_mixer_nids[idx];
        sprintf(name, "%s Playback Switch", pfx);
        if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
@@ -3177,7 +3186,6 @@ static int patch_ad1884(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
-       mutex_init(&spec->amp_mutex);
        codec->spec = spec;
 
        spec->multiout.max_channels = 2;
@@ -3847,7 +3855,6 @@ static int patch_ad1884a(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
-       mutex_init(&spec->amp_mutex);
        codec->spec = spec;
 
        spec->multiout.max_channels = 2;
@@ -4152,7 +4159,6 @@ static int patch_ad1882(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
-       mutex_init(&spec->amp_mutex);
        codec->spec = spec;
 
        spec->multiout.max_channels = 6;
index 36fd852600352244c17e10f6b49c72e284840ea0..7c1eb23f0cec09ae31901058b11222b1ddeca6e4 100644 (file)
@@ -82,7 +82,6 @@ struct conexant_spec {
        /* PCM information */
        struct hda_pcm pcm_rec[2];      /* used in build_pcms() */
 
-       struct mutex amp_mutex; /* PCM volume/mute control mutex */
        unsigned int spdif_route;
 
        /* dynamic controls, init_verbs and input_mux */
@@ -687,7 +686,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
 
 static struct hda_verb cxt5045_init_verbs[] = {
        /* Line in, Mic */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
        /* HP, Amp  */
        {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
@@ -907,10 +906,12 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
        SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
        SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
-       SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505",
+                     CXT5045_LAPTOP_HPMICSENSE),
        SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
        SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
        SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
@@ -928,7 +929,6 @@ static int patch_cxt5045(struct hda_codec *codec)
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
                return -ENOMEM;
-       mutex_init(&spec->amp_mutex);
        codec->spec = spec;
 
        spec->multiout.max_channels = 2;
@@ -963,6 +963,7 @@ static int patch_cxt5045(struct hda_codec *codec)
                codec->patch_ops.init = cxt5045_init;
                break;
        case CXT5045_LAPTOP_MICSENSE:
+               codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
                spec->input_mux = &cxt5045_capture_source;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = cxt5045_mic_sense_init_verbs;
@@ -1007,15 +1008,19 @@ static int patch_cxt5045(struct hda_codec *codec)
 #endif 
        }
 
-       /*
-        * Fix max PCM level to 0 dB
-        * (originall it has 0x2b steps with 0dB offset 0x14)
-        */
-       snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
-                                 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+       switch (codec->subsystem_id >> 16) {
+       case 0x103c:
+               /* HP laptop has a really bad sound over 0dB on NID 0x17.
+                * Fix max PCM level to 0 dB
+                * (originall it has 0x2b steps with 0dB offset 0x14)
+                */
+               snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+                                         (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (1 << AC_AMPCAP_MUTE_SHIFT));
+               break;
+       }
 
        return 0;
 }
@@ -1477,7 +1482,6 @@ static int patch_cxt5047(struct hda_codec *codec)
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
                return -ENOMEM;
-       mutex_init(&spec->amp_mutex);
        codec->spec = spec;
 
        spec->multiout.max_channels = 2;
@@ -1736,7 +1740,6 @@ static int patch_cxt5051(struct hda_codec *codec)
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
                return -ENOMEM;
-       mutex_init(&spec->amp_mutex);
        codec->spec = spec;
 
        codec->patch_ops = conexant_patch_ops;
index b0a2a262ece2f0101f8f885c0637ab37fd6e0ae6..2807bc840d26973f695d6be66c55b6bb5ac58717 100644 (file)
@@ -163,6 +163,10 @@ enum {
        ALC662_LENOVO_101E,
        ALC662_ASUS_EEEPC_P701,
        ALC662_ASUS_EEEPC_EP20,
+       ALC663_ASUS_M51VA,
+       ALC663_ASUS_G71V,
+       ALC663_ASUS_H13,
+       ALC663_ASUS_G50V,
        ALC662_AUTO,
        ALC662_MODEL_LAST,
 };
@@ -205,6 +209,7 @@ enum {
        ALC883_MITAC,
        ALC883_CLEVO_M720,
        ALC883_FUJITSU_PI2515,
+       ALC883_3ST_6ch_INTEL,
        ALC883_AUTO,
        ALC883_MODEL_LAST,
 };
@@ -280,6 +285,10 @@ struct alc_spec {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
 #endif
+
+       /* for PLL fix */
+       hda_nid_t pll_nid;
+       unsigned int pll_coef_idx, pll_coef_bit;
 };
 
 /*
@@ -747,6 +756,38 @@ static struct hda_verb alc_gpio3_init_verbs[] = {
        { }
 };
 
+/*
+ * Fix hardware PLL issue
+ * On some codecs, the analog PLL gating control must be off while
+ * the default value is 1.
+ */
+static void alc_fix_pll(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int val;
+
+       if (!spec->pll_nid)
+               return;
+       snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
+                           spec->pll_coef_idx);
+       val = snd_hda_codec_read(codec, spec->pll_nid, 0,
+                                AC_VERB_GET_PROC_COEF, 0);
+       snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
+                           spec->pll_coef_idx);
+       snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
+                           val & ~(1 << spec->pll_coef_bit));
+}
+
+static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+                            unsigned int coef_idx, unsigned int coef_bit)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->pll_nid = nid;
+       spec->pll_coef_idx = coef_idx;
+       spec->pll_coef_bit = coef_bit;
+       alc_fix_pll(codec);
+}
+
 static void alc_sku_automute(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -776,6 +817,24 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
        alc_sku_automute(codec);
 }
 
+/* additional initialization for ALC888 variants */
+static void alc888_coef_init(struct hda_codec *codec)
+{
+       unsigned int tmp;
+
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
+       tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
+       if ((tmp & 0xf0) == 2)
+               /* alc888S-VC */
+               snd_hda_codec_read(codec, 0x20, 0,
+                                  AC_VERB_SET_PROC_COEF, 0x830);
+        else
+                /* alc888-VB */
+                snd_hda_codec_read(codec, 0x20, 0,
+                                   AC_VERB_SET_PROC_COEF, 0x3030);
+}
+
 /* 32-bit subsystem ID for BIOS loading in HD Audio codec.
  *     31 ~ 16 :       Manufacture ID
  *     15 ~ 8  :       SKU ID
@@ -851,8 +910,10 @@ do_sku:
                case 0x10ec0267:
                case 0x10ec0268:
                case 0x10ec0269:
+               case 0x10ec0660:
+               case 0x10ec0662:
+               case 0x10ec0663:
                case 0x10ec0862:
-               case 0x10ec0662:        
                case 0x10ec0889:
                        snd_hda_codec_write(codec, 0x14, 0,
                                            AC_VERB_SET_EAPD_BTLENABLE, 2);
@@ -877,7 +938,6 @@ do_sku:
                case 0x10ec0882:
                case 0x10ec0883:
                case 0x10ec0885:
-               case 0x10ec0888:
                case 0x10ec0889:
                        snd_hda_codec_write(codec, 0x20, 0,
                                            AC_VERB_SET_COEF_INDEX, 7);
@@ -889,6 +949,9 @@ do_sku:
                                            AC_VERB_SET_PROC_COEF,
                                            tmp | 0x2010);
                        break;
+               case 0x10ec0888:
+                       alc888_coef_init(codec);
+                       break;
                case 0x10ec0267:
                case 0x10ec0268:
                        snd_hda_codec_write(codec, 0x20, 0,
@@ -2373,6 +2436,8 @@ static int alc_init(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        unsigned int i;
 
+       alc_fix_pll(codec);
+
        for (i = 0; i < spec->num_init_verbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
@@ -3009,6 +3074,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+       SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
        SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
        SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
        SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
@@ -5101,7 +5167,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
-       SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP),
+       SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
        SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
@@ -6127,6 +6193,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
        SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
@@ -6353,7 +6420,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec)
                        continue;
                vref = PIN_IN;
                if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
-                       if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) &
+                       unsigned int pincap;
+                       pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
+                       if ((pincap >> AC_PINCAP_VREF_SHIFT) &
                            AC_PINCAP_VREF_80)
                                vref = PIN_VREF80;
                }
@@ -6450,8 +6519,9 @@ static int patch_alc882(struct hda_codec *codec)
                case 0x106b1000: /* iMac 24 */
                        board_config = ALC885_IMAC24;
                        break;
-               case 0x106b00a1: /* Macbook */
+               case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
                case 0x106b2c00: /* Macbook Pro rev3 */
+               case 0x106b3600: /* Macbook 3.1 */
                        board_config = ALC885_MBP3;
                        break;
                default:
@@ -6485,14 +6555,20 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config != ALC882_AUTO)
                setup_preset(spec, &alc882_presets[board_config]);
 
-       spec->stream_name_analog = "ALC882 Analog";
+       if (codec->vendor_id == 0x10ec0885) {
+               spec->stream_name_analog = "ALC885 Analog";
+               spec->stream_name_digital = "ALC885 Digital";
+       } else {
+               spec->stream_name_analog = "ALC882 Analog";
+               spec->stream_name_digital = "ALC882 Digital";
+       }
+
        spec->stream_analog_playback = &alc882_pcm_analog_playback;
        spec->stream_analog_capture = &alc882_pcm_analog_capture;
        /* FIXME: setup DAC5 */
        /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
        spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
-       spec->stream_name_digital = "ALC882 Digital";
        spec->stream_digital_playback = &alc882_pcm_digital_playback;
        spec->stream_digital_capture = &alc882_pcm_digital_capture;
 
@@ -6569,6 +6645,16 @@ static struct hda_input_mux alc883_capture_source = {
        },
 };
 
+static struct hda_input_mux alc883_3stack_6ch_intel = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x1 },
+               { "Front Mic", 0x0 },
+               { "Line", 0x2 },
+               { "CD", 0x4 },
+       },
+};
+
 static struct hda_input_mux alc883_lenovo_101e_capture_source = {
        .num_items = 2,
        .items = {
@@ -6649,6 +6735,48 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
        { 6, alc883_3ST_ch6_init },
 };
 
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_3ST_ch2_intel_init[] = {
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_3ST_ch4_intel_init[] = {
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_3ST_ch6_intel_init[] = {
+       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
+       { 2, alc883_3ST_ch2_intel_init },
+       { 4, alc883_3ST_ch4_intel_init },
+       { 6, alc883_3ST_ch6_intel_init },
+};
+
 /*
  * 6ch mode
  */
@@ -6881,15 +7009,54 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -7729,6 +7896,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC883_MITAC]          = "mitac",
        [ALC883_CLEVO_M720]     = "clevo-m720",
        [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
+       [ALC883_3ST_6ch_INTEL]  = "3stack-6ch-intel",
        [ALC883_AUTO]           = "auto",
 };
 
@@ -7786,6 +7954,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
        SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
+       SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
+       SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
        SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
        {}
 };
@@ -7824,6 +7994,18 @@ static struct alc_config_preset alc883_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
        },
+       [ALC883_3ST_6ch_INTEL] = {
+               .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
+               .channel_mode = alc883_3ST_6ch_intel_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_3stack_6ch_intel,
+       },
        [ALC883_6ST_DIG] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
                .init_verbs = { alc883_init_verbs },
@@ -8145,6 +8327,8 @@ static int patch_alc883(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
        board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
                                                  alc883_models,
                                                  alc883_cfg_tbl);
@@ -8171,12 +8355,25 @@ static int patch_alc883(struct hda_codec *codec)
        if (board_config != ALC883_AUTO)
                setup_preset(spec, &alc883_presets[board_config]);
 
-       spec->stream_name_analog = "ALC883 Analog";
+       switch (codec->vendor_id) {
+       case 0x10ec0888:
+               spec->stream_name_analog = "ALC888 Analog";
+               spec->stream_name_digital = "ALC888 Digital";
+               break;
+       case 0x10ec0889:
+               spec->stream_name_analog = "ALC889 Analog";
+               spec->stream_name_digital = "ALC889 Digital";
+               break;
+       default:
+               spec->stream_name_analog = "ALC883 Analog";
+               spec->stream_name_digital = "ALC883 Digital";
+               break;
+       }
+
        spec->stream_analog_playback = &alc883_pcm_analog_playback;
        spec->stream_analog_capture = &alc883_pcm_analog_capture;
        spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
 
-       spec->stream_name_digital = "ALC883 Digital";
        spec->stream_digital_playback = &alc883_pcm_digital_playback;
        spec->stream_digital_capture = &alc883_pcm_digital_capture;
 
@@ -8189,6 +8386,9 @@ static int patch_alc883(struct hda_codec *codec)
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC883_AUTO)
                spec->init_hook = alc883_auto_init;
+       else if (codec->vendor_id == 0x10ec0888)
+               spec->init_hook = alc888_coef_init;
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc883_loopbacks;
@@ -9522,6 +9722,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
+                     ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
@@ -9729,6 +9931,8 @@ static int patch_alc262(struct hda_codec *codec)
        }
 #endif
 
+       alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
        board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
                                                  alc262_models,
                                                  alc262_cfg_tbl);
@@ -10674,12 +10878,18 @@ static int patch_alc268(struct hda_codec *codec)
        if (board_config != ALC268_AUTO)
                setup_preset(spec, &alc268_presets[board_config]);
 
-       spec->stream_name_analog = "ALC268 Analog";
+       if (codec->vendor_id == 0x10ec0267) {
+               spec->stream_name_analog = "ALC267 Analog";
+               spec->stream_name_digital = "ALC267 Digital";
+       } else {
+               spec->stream_name_analog = "ALC268 Analog";
+               spec->stream_name_digital = "ALC268 Digital";
+       }
+
        spec->stream_analog_playback = &alc268_pcm_analog_playback;
        spec->stream_analog_capture = &alc268_pcm_analog_capture;
        spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
 
-       spec->stream_name_digital = "ALC268 Digital";
        spec->stream_digital_playback = &alc268_pcm_digital_playback;
 
        if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
@@ -11033,6 +11243,8 @@ static int patch_alc269(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
        board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
                                                  alc269_models,
                                                  alc269_cfg_tbl);
@@ -12631,6 +12843,12 @@ static struct hda_verb alc861vd_eapd_verbs[] = {
        { }
 };
 
+static struct hda_verb alc660vd_eapd_verbs[] = {
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
 static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -12786,6 +13004,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
        SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
        {}
 };
@@ -13168,11 +13387,19 @@ static int patch_alc861vd(struct hda_codec *codec)
        if (board_config != ALC861VD_AUTO)
                setup_preset(spec, &alc861vd_presets[board_config]);
 
-       spec->stream_name_analog = "ALC861VD Analog";
+       if (codec->vendor_id == 0x10ec0660) {
+               spec->stream_name_analog = "ALC660-VD Analog";
+               spec->stream_name_digital = "ALC660-VD Digital";
+               /* always turn on EAPD */
+               spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs;
+       } else {
+               spec->stream_name_analog = "ALC861VD Analog";
+               spec->stream_name_digital = "ALC861VD Digital";
+       }
+
        spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
        spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
 
-       spec->stream_name_digital = "ALC861VD Digital";
        spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
        spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
 
@@ -13251,6 +13478,23 @@ static struct hda_input_mux alc662_eeepc_capture_source = {
        },
 };
 
+static struct hda_input_mux alc663_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+       },
+};
+
+static struct hda_input_mux alc663_m51va_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Ext-Mic", 0x0 },
+               { "D-Mic", 0x9 },
+       },
+};
+
 #define alc662_mux_enum_info alc_mux_enum_info
 #define alc662_mux_enum_get alc_mux_enum_get
 #define alc662_mux_enum_put alc882_mux_enum_put
@@ -13431,6 +13675,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc663_m51va_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc663_g71v_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc663_g50v_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc662_chmode_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -13501,6 +13783,11 @@ static struct hda_verb alc662_init_verbs[] = {
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /* always trun on EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+
        { }
 };
 
@@ -13571,6 +13858,43 @@ static struct hda_verb alc662_auto_init_verbs[] = {
        { }
 };
 
+static struct hda_verb alc663_m51va_init_verbs[] = {
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
+
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc663_g71v_init_verbs[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
+       /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
+
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
+       {}
+};
+
+static struct hda_verb alc663_g50v_init_verbs[] = {
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Headphone */
+
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+       {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new alc662_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
@@ -13692,6 +14016,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
        alc662_eeepc_ep20_automute(codec);
 }
 
+static void alc663_m51va_speaker_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x21, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+}
+
+static void alc663_m51va_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+       snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+       snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
+       snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+       snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
+}
+
+static void alc663_m51va_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_m51va_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc663_m51va_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_m51va_inithook(struct hda_codec *codec)
+{
+       alc663_m51va_speaker_automute(codec);
+       alc663_m51va_mic_automute(codec);
+}
+
+static void alc663_g71v_hp_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x21, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+}
+
+static void alc663_g71v_front_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0)
+               & AC_PINSENSE_PRESENCE;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, bits);
+}
+
+static void alc663_g71v_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_g71v_hp_automute(codec);
+               break;
+       case ALC880_FRONT_EVENT:
+               alc663_g71v_front_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_g71v_inithook(struct hda_codec *codec)
+{
+       alc663_g71v_front_automute(codec);
+       alc663_g71v_hp_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+
+static void alc663_g50v_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc663_m51va_speaker_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc662_eeepc_mic_automute(codec);
+               break;
+       }
+}
+
+static void alc663_g50v_inithook(struct hda_codec *codec)
+{
+       alc663_m51va_speaker_automute(codec);
+       alc662_eeepc_mic_automute(codec);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks       alc880_loopbacks
 #endif
@@ -13714,14 +14157,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
        [ALC662_LENOVO_101E]    = "lenovo-101e",
        [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
        [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
+       [ALC663_ASUS_M51VA] = "m51va",
+       [ALC663_ASUS_G71V] = "g71v",
+       [ALC663_ASUS_H13] = "h13",
+       [ALC663_ASUS_G50V] = "g50v",
        [ALC662_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
+       SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
+       SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
        SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
        SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
+       SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
+       SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
+       SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
        {}
 };
 
@@ -13809,7 +14262,53 @@ static struct alc_config_preset alc662_presets[] = {
                .unsol_event = alc662_eeepc_ep20_unsol_event,
                .init_hook = alc662_eeepc_ep20_inithook,
        },
-
+       [ALC663_ASUS_M51VA] = {
+               .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+               .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc663_m51va_capture_source,
+               .unsol_event = alc663_m51va_unsol_event,
+               .init_hook = alc663_m51va_inithook,
+       },
+       [ALC663_ASUS_G71V] = {
+               .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
+               .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc662_eeepc_capture_source,
+               .unsol_event = alc663_g71v_unsol_event,
+               .init_hook = alc663_g71v_inithook,
+       },
+       [ALC663_ASUS_H13] = {
+               .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
+               .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
+               .channel_mode = alc662_3ST_2ch_modes,
+               .input_mux = &alc663_m51va_capture_source,
+               .unsol_event = alc663_m51va_unsol_event,
+               .init_hook = alc663_m51va_inithook,
+       },
+       [ALC663_ASUS_G50V] = {
+               .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
+               .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .dig_out_nid = ALC662_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+               .channel_mode = alc662_3ST_6ch_modes,
+               .input_mux = &alc663_capture_source,
+               .unsol_event = alc663_g50v_unsol_event,
+               .init_hook = alc663_g50v_inithook,
+       },
 };
 
 
@@ -14082,6 +14581,8 @@ static int patch_alc662(struct hda_codec *codec)
 
        codec->spec = spec;
 
+       alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
        board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
                                                  alc662_models,
                                                  alc662_cfg_tbl);
@@ -14108,11 +14609,17 @@ static int patch_alc662(struct hda_codec *codec)
        if (board_config != ALC662_AUTO)
                setup_preset(spec, &alc662_presets[board_config]);
 
-       spec->stream_name_analog = "ALC662 Analog";
+       if (codec->vendor_id == 0x10ec0663) {
+               spec->stream_name_analog = "ALC663 Analog";
+               spec->stream_name_digital = "ALC663 Digital";
+       } else {
+               spec->stream_name_analog = "ALC662 Analog";
+               spec->stream_name_digital = "ALC662 Digital";
+       }
+
        spec->stream_analog_playback = &alc662_pcm_analog_playback;
        spec->stream_analog_capture = &alc662_pcm_analog_capture;
 
-       spec->stream_name_digital = "ALC662 Digital";
        spec->stream_digital_playback = &alc662_pcm_digital_playback;
        spec->stream_digital_capture = &alc662_pcm_digital_capture;
 
@@ -14151,6 +14658,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
          .patch = patch_alc883 },
        { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
          .patch = patch_alc662 },
+       { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
        { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
        { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
        { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
index a4f44a00bae8eb548708a0dd8903cf0bf652bbb3..08cb77f51880a31265c46cf66691715cfbf5dd55 100644 (file)
@@ -636,21 +636,28 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
        { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 };
 
+#define HD_DISABLE_PORTF 3
 static struct hda_verb stac92hd71bxx_analog_core_init[] = {
+       /* start of config #1 */
+
+       /* connect port 0f to audio mixer */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
+       /* unmute right and left channels for node 0x0f */
+       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       /* start of config #2 */
+
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
        /* connect headphone jack to dac1 */
        { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* connect ports 0d and 0f to audio mixer */
+       /* connect port 0d to audio mixer */
        { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
-       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
-       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
        /* unmute dac0 input in audio mixer */
        { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
-       /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+       /* unmute right and left channels for nodes 0x0a, 0xd */
        { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {}
 };
 
@@ -818,6 +825,9 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
 
+       HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
+
        HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
        HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
        { } /* end */
@@ -1317,13 +1327,13 @@ static unsigned int ref92hd71bxx_pin_configs[10] = {
        0x90a000f0, 0x01452050,
 };
 
-static unsigned int dell_m4_1_pin_configs[13] = {
+static unsigned int dell_m4_1_pin_configs[10] = {
        0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0,
        0x40f000f0, 0x4f0000f0,
 };
 
-static unsigned int dell_m4_2_pin_configs[13] = {
+static unsigned int dell_m4_2_pin_configs[10] = {
        0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
        0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
        0x40f000f0, 0x044413b0,
@@ -1754,12 +1764,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
                      "unknown Dell", STAC_9205_DELL_M42),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
                      "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
-                         "Dell Precision", STAC_9205_DELL_M43),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
                      "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
-                     "Dell Precision", STAC_9205_DELL_M43),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
                      "Dell Precision", STAC_9205_DELL_M43),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
@@ -1770,18 +1776,14 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
                      "Dell Precision", STAC_9205_DELL_M43),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
                      "Dell Precision M4300", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
-                     "Dell Inspiron", STAC_9205_DELL_M44),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
-                     "Dell Inspiron", STAC_9205_DELL_M44),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
-                     "Dell Inspiron", STAC_9205_DELL_M44),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
-                     "Dell Inspiron", STAC_9205_DELL_M44),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
                      "unknown Dell", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
+                     "Dell Precision", STAC_9205_DELL_M43),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
                      "Dell Inspiron", STAC_9205_DELL_M44),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
@@ -3103,13 +3105,16 @@ static int stac92xx_init(struct hda_codec *codec)
                                        0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
                                        0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+               def_conf = get_defcfg_connect(def_conf);
                /* outputs are only ports capable of power management
                 * any attempts on powering down a input port cause the
                 * referenced VREF to act quirky.
                 */
                if (pinctl & AC_PINCTL_IN_EN)
                        continue;
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
+               /* skip any ports that don't have jacks since presence
+                * detection is useless */
+               if (def_conf && def_conf != AC_JACK_PORT_FIXED)
                        continue;
                enable_pin_detect(codec, spec->pwr_nids[i], event | i);
                codec->patch_ops.unsol_event(codec, (event | i) << 26);
@@ -3614,6 +3619,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 
        codec->spec = spec;
        spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
+       spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
        spec->pin_nids = stac92hd71bxx_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec,
                                                        STAC_92HD71BXX_MODELS,
@@ -3642,6 +3648,19 @@ again:
                spec->mixer = stac92hd71bxx_mixer;
                spec->init = stac92hd71bxx_core_init;
                break;
+       case 0x111d7608: /* 5 Port with Analog Mixer */
+               /* no output amps */
+               spec->num_pwrs = 0;
+               spec->mixer = stac92hd71bxx_analog_mixer;
+
+               /* disable VSW */
+               spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
+               stac92xx_set_config_reg(codec, 0xf, 0x40f000f0);
+               break;
+       case 0x111d7603: /* 6 Port with Analog Mixer */
+               /* no output amps */
+               spec->num_pwrs = 0;
+               /* fallthru */
        default:
                spec->mixer = stac92hd71bxx_analog_mixer;
                spec->init = stac92hd71bxx_analog_core_init;
@@ -3653,22 +3672,19 @@ again:
        /* GPIO0 High = EAPD */
        spec->gpio_mask = 0x01;
        spec->gpio_dir = 0x01;
-       spec->gpio_mask = 0x01;
        spec->gpio_data = 0x01;
 
        spec->mux_nids = stac92hd71bxx_mux_nids;
        spec->adc_nids = stac92hd71bxx_adc_nids;
        spec->dmic_nids = stac92hd71bxx_dmic_nids;
        spec->dmux_nids = stac92hd71bxx_dmux_nids;
+       spec->pwr_nids = stac92hd71bxx_pwr_nids;
 
        spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
        spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
        spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
 
-       spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
-       spec->pwr_nids = stac92hd71bxx_pwr_nids;
-
        spec->multiout.num_dacs = 1;
        spec->multiout.hp_nid = 0x11;
        spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
@@ -4306,10 +4322,11 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
        { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
        { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
+       { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
+       { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
        { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
        { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
        { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
-       { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
        { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
        { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
        { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
index 43b9e3e858be3d7a6297ab70b7bfd382cbf7fb08..a0c5e009bb4a23eaf4c4ddc97148ed34aea25f36 100644 (file)
@@ -93,9 +93,13 @@ enum {
 #define VT1724_REG_MPU_TXFIFO          0x0a    /*byte ro. number of bytes in TX fifo*/
 #define VT1724_REG_MPU_RXFIFO          0x0b    /*byte ro. number of bytes in RX fifo*/
 
-//are these 2 the wrong way around? they don't seem to be used yet anyway
-#define VT1724_REG_MPU_CTRL            0x0c    /* byte */
-#define VT1724_REG_MPU_DATA            0x0d    /* byte */
+#define VT1724_REG_MPU_DATA            0x0c    /* byte */
+#define VT1724_REG_MPU_CTRL            0x0d    /* byte */
+#define   VT1724_MPU_UART      0x01
+#define   VT1724_MPU_TX_EMPTY  0x02
+#define   VT1724_MPU_TX_FULL   0x04
+#define   VT1724_MPU_RX_EMPTY  0x08
+#define   VT1724_MPU_RX_FULL   0x10
 
 #define VT1724_REG_MPU_FIFO_WM 0x0e    /*byte set the high/low watermarks for RX/TX fifos*/
 #define   VT1724_MPU_RX_FIFO   0x20    //1=rx fifo watermark 0=tx fifo watermark
index 3208901c740e075166f95bc1b8d51406ab88ba56..762fbd7a750710dec0ede3ee426f20cc70668b2f 100644 (file)
@@ -333,6 +333,8 @@ struct snd_ice1712 {
        unsigned int has_spdif: 1;      /* VT1720/4 - has SPDIF I/O */
        unsigned int force_pdma4: 1;    /* VT1720/4 - PDMA4 as non-spdif */
        unsigned int force_rdma1: 1;    /* VT1720/4 - RDMA1 as non-spdif */
+       unsigned int midi_output: 1;    /* VT1720/4: MIDI output triggered */
+       unsigned int midi_input: 1;     /* VT1720/4: MIDI input triggered */
        unsigned int num_total_dacs;    /* total DACs */
        unsigned int num_total_adcs;    /* total ADCs */
        unsigned int cur_rate;          /* current rate */
index 67350901772ce986582ef19e0b8ce9dad738f9cb..e596d777d9dde630d12532c55a578937f8d5b2ee 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
-#include <sound/mpu401.h>
+#include <sound/rawmidi.h>
 #include <sound/initval.h>
 
 #include <sound/asoundef.h>
@@ -223,30 +223,153 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice)
 }
 
 /*
- * MPU401 accessor
+ * MIDI
  */
-static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu,
-                                           unsigned long addr)
+
+static void vt1724_midi_clear_rx(struct snd_ice1712 *ice)
+{
+       unsigned int count;
+
+       for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count)
+               inb(ICEREG1724(ice, MPU_DATA));
+}
+
+static inline struct snd_rawmidi_substream *
+get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream)
 {
-       /* fix status bits to the standard position */
-       /* only RX_EMPTY and TX_FULL are checked */
-       if (addr == MPU401C(mpu))
-               return (inb(addr) & 0x0c) << 4;
+       return list_first_entry(&ice->rmidi[0]->streams[stream].substreams,
+                               struct snd_rawmidi_substream, list);
+}
+
+static void vt1724_midi_write(struct snd_ice1712 *ice)
+{
+       struct snd_rawmidi_substream *s;
+       int count, i;
+       u8 buffer[32];
+
+       s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT);
+       count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO));
+       if (count > 0) {
+               count = snd_rawmidi_transmit(s, buffer, count);
+               for (i = 0; i < count; ++i)
+                       outb(buffer[i], ICEREG1724(ice, MPU_DATA));
+       }
+}
+
+static void vt1724_midi_read(struct snd_ice1712 *ice)
+{
+       struct snd_rawmidi_substream *s;
+       int count, i;
+       u8 buffer[32];
+
+       s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT);
+       count = inb(ICEREG1724(ice, MPU_RXFIFO));
+       if (count > 0) {
+               count = min(count, 32);
+               for (i = 0; i < count; ++i)
+                       buffer[i] = inb(ICEREG1724(ice, MPU_DATA));
+               snd_rawmidi_receive(s, buffer, count);
+       }
+}
+
+static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
+                                  u8 flag, int enable)
+{
+       struct snd_ice1712 *ice = substream->rmidi->private_data;
+       u8 mask;
+
+       spin_lock_irq(&ice->reg_lock);
+       mask = inb(ICEREG1724(ice, IRQMASK));
+       if (enable)
+               mask &= ~flag;
        else
-               return inb(addr);
+               mask |= flag;
+       outb(mask, ICEREG1724(ice, IRQMASK));
+       spin_unlock_irq(&ice->reg_lock);
 }
 
-static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu,
-                                   unsigned char data, unsigned long addr)
+static int vt1724_midi_output_open(struct snd_rawmidi_substream *s)
 {
-       if (addr == MPU401C(mpu)) {
-               if (data == MPU401_ENTER_UART)
-                       outb(0x01, addr);
-               /* what else? */
-       } else
-               outb(data, addr);
+       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1);
+       return 0;
+}
+
+static int vt1724_midi_output_close(struct snd_rawmidi_substream *s)
+{
+       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0);
+       return 0;
 }
 
+static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up)
+{
+       struct snd_ice1712 *ice = s->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ice->reg_lock, flags);
+       if (up) {
+               ice->midi_output = 1;
+               vt1724_midi_write(ice);
+       } else {
+               ice->midi_output = 0;
+       }
+       spin_unlock_irqrestore(&ice->reg_lock, flags);
+}
+
+static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
+{
+       struct snd_ice1712 *ice = s->rmidi->private_data;
+       unsigned long timeout;
+
+       /* 32 bytes should be transmitted in less than about 12 ms */
+       timeout = jiffies + msecs_to_jiffies(15);
+       do {
+               if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY)
+                       break;
+               schedule_timeout_uninterruptible(1);
+       } while (time_after(timeout, jiffies));
+}
+
+static struct snd_rawmidi_ops vt1724_midi_output_ops = {
+       .open = vt1724_midi_output_open,
+       .close = vt1724_midi_output_close,
+       .trigger = vt1724_midi_output_trigger,
+       .drain = vt1724_midi_output_drain,
+};
+
+static int vt1724_midi_input_open(struct snd_rawmidi_substream *s)
+{
+       vt1724_midi_clear_rx(s->rmidi->private_data);
+       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1);
+       return 0;
+}
+
+static int vt1724_midi_input_close(struct snd_rawmidi_substream *s)
+{
+       vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0);
+       return 0;
+}
+
+static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up)
+{
+       struct snd_ice1712 *ice = s->rmidi->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ice->reg_lock, flags);
+       if (up) {
+               ice->midi_input = 1;
+               vt1724_midi_read(ice);
+       } else {
+               ice->midi_input = 0;
+       }
+       spin_unlock_irqrestore(&ice->reg_lock, flags);
+}
+
+static struct snd_rawmidi_ops vt1724_midi_input_ops = {
+       .open = vt1724_midi_input_open,
+       .close = vt1724_midi_input_close,
+       .trigger = vt1724_midi_input_trigger,
+};
+
 
 /*
  *  Interrupt handler
@@ -278,13 +401,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
 #endif
                handled = 1;            
                if (status & VT1724_IRQ_MPU_TX) {
-                       if (ice->rmidi[0])
-                               snd_mpu401_uart_interrupt_tx(irq,
-                                       ice->rmidi[0]->private_data);
-                       else /* disable TX to be sure */
-                               outb(inb(ICEREG1724(ice, IRQMASK)) |
-                                    VT1724_IRQ_MPU_TX,
-                                    ICEREG1724(ice, IRQMASK));
+                       spin_lock(&ice->reg_lock);
+                       if (ice->midi_output)
+                               vt1724_midi_write(ice);
+                       spin_unlock(&ice->reg_lock);
                        /* Due to mysterical reasons, MPU_TX is always
                         * generated (and can't be cleared) when a PCM
                         * playback is going.  So let's ignore at the
@@ -293,13 +413,12 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
                        status_mask &= ~VT1724_IRQ_MPU_TX;
                }
                if (status & VT1724_IRQ_MPU_RX) {
-                       if (ice->rmidi[0])
-                               snd_mpu401_uart_interrupt(irq,
-                                       ice->rmidi[0]->private_data);
-                       else /* disable RX to be sure */
-                               outb(inb(ICEREG1724(ice, IRQMASK)) |
-                                    VT1724_IRQ_MPU_RX,
-                                    ICEREG1724(ice, IRQMASK));
+                       spin_lock(&ice->reg_lock);
+                       if (ice->midi_input)
+                               vt1724_midi_read(ice);
+                       else
+                               vt1724_midi_clear_rx(ice);
+                       spin_unlock(&ice->reg_lock);
                }
                /* ack MPU irq */
                outb(status, ICEREG1724(ice, IRQSTAT));
@@ -2425,28 +2544,30 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
 
        if (! c->no_mpu401) {
                if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
-                       struct snd_mpu401 *mpu;
-                       if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
-                                                      ICEREG1724(ice, MPU_CTRL),
-                                                      (MPU401_INFO_INTEGRATED |
-                                                       MPU401_INFO_NO_ACK |
-                                                       MPU401_INFO_TX_IRQ),
-                                                      ice->irq, 0,
-                                                      &ice->rmidi[0])) < 0) {
+                       struct snd_rawmidi *rmidi;
+
+                       err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi);
+                       if (err < 0) {
                                snd_card_free(card);
                                return err;
                        }
-                       mpu = ice->rmidi[0]->private_data;
-                       mpu->read = snd_vt1724_mpu401_read;
-                       mpu->write = snd_vt1724_mpu401_write;
-                       /* unmask MPU RX/TX irqs */
-                       outb(inb(ICEREG1724(ice, IRQMASK)) &
-                            ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX),
-                            ICEREG1724(ice, IRQMASK));
+                       ice->rmidi[0] = rmidi;
+                       rmidi->private_data = ice;
+                       strcpy(rmidi->name, "ICE1724 MIDI");
+                       rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+                                           SNDRV_RAWMIDI_INFO_INPUT |
+                                           SNDRV_RAWMIDI_INFO_DUPLEX;
+                       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                                           &vt1724_midi_output_ops);
+                       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                                           &vt1724_midi_input_ops);
+
                        /* set watermarks */
                        outb(VT1724_MPU_RX_FIFO | 0x1,
                             ICEREG1724(ice, MPU_FIFO_WM));
                        outb(0x1, ICEREG1724(ice, MPU_FIFO_WM));
+                       /* set UART mode */
+                       outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL));
                }
        }
 
index a536c59fbea1e4faed5155ce579ac0ac800e572b..f4788dee05c36efe80ec6117d66bb469afdeecaa 100644 (file)
@@ -2427,6 +2427,29 @@ snd_m3_amp_enable(struct snd_m3 *chip, int enable)
        outw(0xffff, io + GPIO_MASK);
 }
 
+static void
+snd_m3_hv_init(struct snd_m3 *chip)
+{
+       unsigned long io = chip->iobase;
+       u16 val = GPI_VOL_DOWN | GPI_VOL_UP;
+
+       if (!chip->is_omnibook)
+               return;
+
+       /*
+        * Volume buttons on some HP OmniBook laptops
+        * require some GPIO magic to work correctly.
+        */
+       outw(0xffff, io + GPIO_MASK);
+       outw(0x0000, io + GPIO_DATA);
+
+       outw(~val, io + GPIO_MASK);
+       outw(inw(io + GPIO_DIRECTION) & ~val, io + GPIO_DIRECTION);
+       outw(val, io + GPIO_MASK);
+
+       outw(0xffff, io + GPIO_MASK);
+}
+
 static int
 snd_m3_chip_init(struct snd_m3 *chip)
 {
@@ -2442,21 +2465,6 @@ snd_m3_chip_init(struct snd_m3 *chip)
               DISABLE_LEGACY);
        pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
 
-       if (chip->is_omnibook) {
-               /*
-                * Volume buttons on some HP OmniBook laptops don't work
-                * correctly. This makes them work for the most part.
-                *
-                * Volume up and down buttons on the laptop side work.
-                * Fn+cursor_up (volme up) works.
-                * Fn+cursor_down (volume down) doesn't work.
-                * Fn+F7 (mute) works acts as volume up.
-                */
-               outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK);
-               outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION);
-               outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA);
-               outw(0xffff, io + GPIO_MASK);
-       }
        pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
        n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
        n |= chip->hv_config;
@@ -2642,6 +2650,8 @@ static int m3_resume(struct pci_dev *pci)
        snd_m3_enable_ints(chip);
        snd_m3_amp_enable(chip, 1);
 
+       snd_m3_hv_init(chip);
+
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
@@ -2781,6 +2791,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
 
        snd_m3_amp_enable(chip, 1);
 
+       snd_m3_hv_init(chip);
+
        tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
 
        if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
index 7efb838d18a6b3e78c0b5ceedeccc85887187b2c..06d13e7171148d261fdeeccd21563da3ef59d577 100644 (file)
@@ -1302,8 +1302,8 @@ snd_nm256_mixer(struct nm256 *chip)
                .read = snd_nm256_ac97_read,
        };
 
-       chip->ac97_regs = kcalloc(sizeof(short),
-                                 ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL);
+       chip->ac97_regs = kcalloc(ARRAY_SIZE(nm256_ac97_init_val),
+                                 sizeof(short), GFP_KERNEL);
        if (! chip->ac97_regs)
                return -ENOMEM;
 
index 090dd4354a2838fa2e818265270965c829460c34..7442460583dde0c68f92f40c965afe8cbb461272 100644 (file)
@@ -28,7 +28,7 @@
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("TempoTec HiFier driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -62,16 +62,28 @@ static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
                         AK4396_WRITE | (reg << 8) | value);
 }
 
-static void hifier_init(struct oxygen *chip)
+static void update_ak4396_volume(struct oxygen *chip)
+{
+       ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
+       ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
+}
+
+static void hifier_registers_init(struct oxygen *chip)
 {
        struct hifier_data *data = chip->model_data;
 
-       data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
        ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
        ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2);
        ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
-       ak4396_write(chip, AK4396_LCH_ATT, 0);
-       ak4396_write(chip, AK4396_RCH_ATT, 0);
+       update_ak4396_volume(chip);
+}
+
+static void hifier_init(struct oxygen *chip)
+{
+       struct hifier_data *data = chip->model_data;
+
+       data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+       hifier_registers_init(chip);
 
        snd_component_add(chip->card, "AK4396");
        snd_component_add(chip->card, "CS5340");
@@ -100,12 +112,6 @@ static void set_ak4396_params(struct oxygen *chip,
        ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
 }
 
-static void update_ak4396_volume(struct oxygen *chip)
-{
-       ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
-       ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
 static void update_ak4396_mute(struct oxygen *chip)
 {
        struct hifier_data *data = chip->model_data;
@@ -140,6 +146,7 @@ static const struct oxygen_model model_hifier = {
        .init = hifier_init,
        .control_filter = hifier_control_filter,
        .cleanup = hifier_cleanup,
+       .resume = hifier_registers_init,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_cs5340_params,
        .update_dac_volume = update_ak4396_volume,
@@ -180,6 +187,10 @@ static struct pci_driver hifier_driver = {
        .id_table = hifier_ids,
        .probe = hifier_probe,
        .remove = __devexit_p(oxygen_pci_remove),
+#ifdef CONFIG_PM
+       .suspend = oxygen_pci_suspend,
+       .resume = oxygen_pci_resume,
+#endif
 };
 
 static int __init alsa_card_hifier_init(void)
index 63f185c1ed1ed899a0af6786d4092731a87f0c26..7c8ae31eb4685b857488e931a55efcd8f4e1826e 100644 (file)
@@ -43,7 +43,7 @@
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("C-Media CMI8788 driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -80,6 +80,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
 
 struct generic_data {
        u8 ak4396_ctl2;
+       u16 saved_wm8785_registers[2];
 };
 
 static void ak4396_write(struct oxygen *chip, unsigned int codec,
@@ -99,20 +100,35 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec,
 
 static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
 {
+       struct generic_data *data = chip->model_data;
+
        oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
                         OXYGEN_SPI_DATA_LENGTH_2 |
                         OXYGEN_SPI_CLOCK_160 |
                         (3 << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
                         (reg << 9) | value);
+       if (reg < ARRAY_SIZE(data->saved_wm8785_registers))
+               data->saved_wm8785_registers[reg] = value;
 }
 
-static void ak4396_init(struct oxygen *chip)
+static void update_ak4396_volume(struct oxygen *chip)
+{
+       unsigned int i;
+
+       for (i = 0; i < 4; ++i) {
+               ak4396_write(chip, i,
+                            AK4396_LCH_ATT, chip->dac_volume[i * 2]);
+               ak4396_write(chip, i,
+                            AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]);
+       }
+}
+
+static void ak4396_registers_init(struct oxygen *chip)
 {
        struct generic_data *data = chip->model_data;
        unsigned int i;
 
-       data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
        for (i = 0; i < 4; ++i) {
                ak4396_write(chip, i,
                             AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
@@ -120,9 +136,16 @@ static void ak4396_init(struct oxygen *chip)
                             AK4396_CONTROL_2, data->ak4396_ctl2);
                ak4396_write(chip, i,
                             AK4396_CONTROL_3, AK4396_PCM);
-               ak4396_write(chip, i, AK4396_LCH_ATT, 0);
-               ak4396_write(chip, i, AK4396_RCH_ATT, 0);
        }
+       update_ak4396_volume(chip);
+}
+
+static void ak4396_init(struct oxygen *chip)
+{
+       struct generic_data *data = chip->model_data;
+
+       data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+       ak4396_registers_init(chip);
        snd_component_add(chip->card, "AK4396");
 }
 
@@ -133,12 +156,23 @@ static void ak5385_init(struct oxygen *chip)
        snd_component_add(chip->card, "AK5385");
 }
 
-static void wm8785_init(struct oxygen *chip)
+static void wm8785_registers_init(struct oxygen *chip)
 {
+       struct generic_data *data = chip->model_data;
+
        wm8785_write(chip, WM8785_R7, 0);
-       wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE |
-                    WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST);
-       wm8785_write(chip, WM8785_R1, WM8785_WL_24);
+       wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]);
+       wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]);
+}
+
+static void wm8785_init(struct oxygen *chip)
+{
+       struct generic_data *data = chip->model_data;
+
+       data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE |
+               WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
+       data->saved_wm8785_registers[1] = WM8785_WL_24;
+       wm8785_registers_init(chip);
        snd_component_add(chip->card, "WM8785");
 }
 
@@ -158,6 +192,12 @@ static void generic_cleanup(struct oxygen *chip)
 {
 }
 
+static void generic_resume(struct oxygen *chip)
+{
+       ak4396_registers_init(chip);
+       wm8785_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
                              struct snd_pcm_hw_params *params)
 {
@@ -183,18 +223,6 @@ static void set_ak4396_params(struct oxygen *chip,
        }
 }
 
-static void update_ak4396_volume(struct oxygen *chip)
-{
-       unsigned int i;
-
-       for (i = 0; i < 4; ++i) {
-               ak4396_write(chip, i,
-                            AK4396_LCH_ATT, chip->dac_volume[i * 2]);
-               ak4396_write(chip, i,
-                            AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]);
-       }
-}
-
 static void update_ak4396_mute(struct oxygen *chip)
 {
        struct generic_data *data = chip->model_data;
@@ -256,6 +284,7 @@ static const struct oxygen_model model_generic = {
        .owner = THIS_MODULE,
        .init = generic_init,
        .cleanup = generic_cleanup,
+       .resume = generic_resume,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_wm8785_params,
        .update_dac_volume = update_ak4396_volume,
@@ -283,6 +312,7 @@ static const struct oxygen_model model_meridian = {
        .owner = THIS_MODULE,
        .init = meridian_init,
        .cleanup = generic_cleanup,
+       .resume = ak4396_registers_init,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_ak5385_params,
        .update_dac_volume = update_ak4396_volume,
@@ -331,6 +361,10 @@ static struct pci_driver oxygen_driver = {
        .id_table = oxygen_ids,
        .probe = generic_oxygen_probe,
        .remove = __devexit_p(oxygen_pci_remove),
+#ifdef CONFIG_PM
+       .suspend = oxygen_pci_suspend,
+       .resume = oxygen_pci_resume,
+#endif
 };
 
 static int __init alsa_card_oxygen_init(void)
index a71c6e059260543c08b172f4fd71e3bdd0f5eef8..74a6448800747acb0de19ce4eb70db51a4c67f7c 100644 (file)
@@ -16,6 +16,8 @@
 #define PCM_AC97       5
 #define PCM_COUNT      6
 
+#define OXYGEN_IO_SIZE 0x100
+
 /* model-specific configuration of outputs/inputs */
 #define PLAYBACK_0_TO_I2S      0x001
 #define PLAYBACK_1_TO_SPDIF    0x004
@@ -78,6 +80,12 @@ struct oxygen {
        struct work_struct spdif_input_bits_work;
        struct work_struct gpio_work;
        wait_queue_head_t ac97_waitqueue;
+       union {
+               u8 _8[OXYGEN_IO_SIZE];
+               __le16 _16[OXYGEN_IO_SIZE / 2];
+               __le32 _32[OXYGEN_IO_SIZE / 4];
+       } saved_registers;
+       u16 saved_ac97_registers[2][0x40];
 };
 
 struct oxygen_model {
@@ -89,6 +97,8 @@ struct oxygen_model {
        int (*control_filter)(struct snd_kcontrol_new *template);
        int (*mixer_init)(struct oxygen *chip);
        void (*cleanup)(struct oxygen *chip);
+       void (*suspend)(struct oxygen *chip);
+       void (*resume)(struct oxygen *chip);
        void (*pcm_hardware_filter)(unsigned int channel,
                                    struct snd_pcm_hardware *hardware);
        void (*set_dac_params)(struct oxygen *chip,
@@ -117,6 +127,10 @@ struct oxygen_model {
 int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
                     const struct oxygen_model *model);
 void oxygen_pci_remove(struct pci_dev *pci);
+#ifdef CONFIG_PM
+int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state);
+int oxygen_pci_resume(struct pci_dev *pci);
+#endif
 
 /* oxygen_mixer.c */
 
index 5569606ee87ff22bfb0ac9b9a15e9635e7bd4ed4..83f135f80df44439f62aed9f0b2e3b72d76172a8 100644 (file)
@@ -44,18 +44,21 @@ EXPORT_SYMBOL(oxygen_read32);
 void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value)
 {
        outb(value, chip->addr + reg);
+       chip->saved_registers._8[reg] = value;
 }
 EXPORT_SYMBOL(oxygen_write8);
 
 void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value)
 {
        outw(value, chip->addr + reg);
+       chip->saved_registers._16[reg / 2] = cpu_to_le16(value);
 }
 EXPORT_SYMBOL(oxygen_write16);
 
 void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value)
 {
        outl(value, chip->addr + reg);
+       chip->saved_registers._32[reg / 4] = cpu_to_le32(value);
 }
 EXPORT_SYMBOL(oxygen_write32);
 
@@ -63,7 +66,10 @@ void oxygen_write8_masked(struct oxygen *chip, unsigned int reg,
                          u8 value, u8 mask)
 {
        u8 tmp = inb(chip->addr + reg);
-       outb((tmp & ~mask) | (value & mask), chip->addr + reg);
+       tmp &= ~mask;
+       tmp |= value & mask;
+       outb(tmp, chip->addr + reg);
+       chip->saved_registers._8[reg] = tmp;
 }
 EXPORT_SYMBOL(oxygen_write8_masked);
 
@@ -71,7 +77,10 @@ void oxygen_write16_masked(struct oxygen *chip, unsigned int reg,
                           u16 value, u16 mask)
 {
        u16 tmp = inw(chip->addr + reg);
-       outw((tmp & ~mask) | (value & mask), chip->addr + reg);
+       tmp &= ~mask;
+       tmp |= value & mask;
+       outw(tmp, chip->addr + reg);
+       chip->saved_registers._16[reg / 2] = cpu_to_le16(tmp);
 }
 EXPORT_SYMBOL(oxygen_write16_masked);
 
@@ -79,7 +88,10 @@ void oxygen_write32_masked(struct oxygen *chip, unsigned int reg,
                           u32 value, u32 mask)
 {
        u32 tmp = inl(chip->addr + reg);
-       outl((tmp & ~mask) | (value & mask), chip->addr + reg);
+       tmp &= ~mask;
+       tmp |= value & mask;
+       outl(tmp, chip->addr + reg);
+       chip->saved_registers._32[reg / 4] = cpu_to_le32(tmp);
 }
 EXPORT_SYMBOL(oxygen_write32_masked);
 
@@ -128,8 +140,10 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
                oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
                /* require two "completed" writes, just to be sure */
                if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 &&
-                   ++succeeded >= 2)
+                   ++succeeded >= 2) {
+                       chip->saved_ac97_registers[codec][index / 2] = data;
                        return;
+               }
        }
        snd_printk(KERN_ERR "AC'97 write timeout\n");
 }
index 897697d43506d2354b2ffc954f58232d97b3c556..22f37851045e9639032b55960abcd3edb88c973e 100644 (file)
@@ -32,7 +32,7 @@
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("C-Media CMI8788 helper library");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 
 
 static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
@@ -173,7 +173,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
        int i, j;
 
        snd_iprintf(buffer, "CMI8788\n\n");
-       for (i = 0; i < 0x100; i += 0x10) {
+       for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) {
                snd_iprintf(buffer, "%02x:", i);
                for (j = 0; j < 0x10; ++j)
                        snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j));
@@ -314,6 +314,10 @@ static void oxygen_init(struct oxygen *chip)
                                    OXYGEN_SPDIF_LOCK_MASK |
                                    OXYGEN_SPDIF_RATE_MASK);
        oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits);
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_STANDARD);
        oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK);
        oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0);
        oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0);
@@ -455,7 +459,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        }
 
        if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) ||
-           pci_resource_len(pci, 0) < 0x100) {
+           pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) {
                snd_printk(KERN_ERR "invalid PCI I/O range\n");
                err = -ENXIO;
                goto err_pci_regions;
@@ -534,3 +538,99 @@ void oxygen_pci_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 EXPORT_SYMBOL(oxygen_pci_remove);
+
+#ifdef CONFIG_PM
+int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct oxygen *chip = card->private_data;
+       unsigned int i, saved_interrupt_mask;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+       for (i = 0; i < PCM_COUNT; ++i)
+               if (chip->streams[i])
+                       snd_pcm_suspend(chip->streams[i]);
+
+       if (chip->model->suspend)
+               chip->model->suspend(chip);
+
+       spin_lock_irq(&chip->reg_lock);
+       saved_interrupt_mask = chip->interrupt_mask;
+       chip->interrupt_mask = 0;
+       oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
+       spin_unlock_irq(&chip->reg_lock);
+
+       synchronize_irq(chip->irq);
+       flush_scheduled_work();
+       chip->interrupt_mask = saved_interrupt_mask;
+
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       pci_set_power_state(pci, pci_choose_state(pci, state));
+       return 0;
+}
+EXPORT_SYMBOL(oxygen_pci_suspend);
+
+static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = {
+       0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff,
+       0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000
+};
+static const u32 ac97_registers_to_restore[2][0x40 / 32] = {
+       { 0x18284fa2, 0x03060000 },
+       { 0x00007fa6, 0x00200000 }
+};
+
+static inline int is_bit_set(const u32 *bitmap, unsigned int bit)
+{
+       return bitmap[bit / 32] & (1 << (bit & 31));
+}
+
+static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec)
+{
+       unsigned int i;
+
+       oxygen_write_ac97(chip, codec, AC97_RESET, 0);
+       msleep(1);
+       for (i = 1; i < 0x40; ++i)
+               if (is_bit_set(ac97_registers_to_restore[codec], i))
+                       oxygen_write_ac97(chip, codec, i * 2,
+                                         chip->saved_ac97_registers[codec][i]);
+}
+
+int oxygen_pci_resume(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct oxygen *chip = card->private_data;
+       unsigned int i;
+
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
+       if (pci_enable_device(pci) < 0) {
+               snd_printk(KERN_ERR "cannot reenable device");
+               snd_card_disconnect(card);
+               return -EIO;
+       }
+       pci_set_master(pci);
+
+       oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
+       for (i = 0; i < OXYGEN_IO_SIZE; ++i)
+               if (is_bit_set(registers_to_restore, i))
+                       oxygen_write8(chip, i, chip->saved_registers._8[i]);
+       if (chip->has_ac97_0)
+               oxygen_restore_ac97(chip, 0);
+       if (chip->has_ac97_1)
+               oxygen_restore_ac97(chip, 1);
+
+       if (chip->model->resume)
+               chip->model->resume(chip);
+
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+EXPORT_SYMBOL(oxygen_pci_resume);
+#endif /* CONFIG_PM */
index b17c405e069df5349daceba5db00416de012eb1b..c4ad65a3406fd61ea6bcb016d8b979def759691a 100644 (file)
 #include <sound/pcm_params.h>
 #include "oxygen.h"
 
+/* most DMA channels have a 16-bit counter for 32-bit words */
+#define BUFFER_BYTES_MAX               ((1 << 16) * 4)
+/* the multichannel DMA channel has a 24-bit counter */
+#define BUFFER_BYTES_MAX_MULTICH       ((1 << 24) * 4)
+
+#define PERIOD_BYTES_MIN               64
+
+#define DEFAULT_BUFFER_BYTES           (BUFFER_BYTES_MAX / 2)
+#define DEFAULT_BUFFER_BYTES_MULTICH   (1024 * 1024)
+
 static const struct snd_pcm_hardware oxygen_stereo_hardware = {
        .info = SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_MMAP_VALID |
@@ -44,11 +54,11 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
        .rate_max = 192000,
        .channels_min = 2,
        .channels_max = 2,
-       .buffer_bytes_max = 256 * 1024,
-       .period_bytes_min = 128,
-       .period_bytes_max = 128 * 1024,
+       .buffer_bytes_max = BUFFER_BYTES_MAX,
+       .period_bytes_min = PERIOD_BYTES_MIN,
+       .period_bytes_max = BUFFER_BYTES_MAX / 2,
        .periods_min = 2,
-       .periods_max = 2048,
+       .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
        .info = SNDRV_PCM_INFO_MMAP |
@@ -70,11 +80,11 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
        .rate_max = 192000,
        .channels_min = 2,
        .channels_max = 8,
-       .buffer_bytes_max = 2048 * 1024,
-       .period_bytes_min = 128,
-       .period_bytes_max = 256 * 1024,
+       .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
+       .period_bytes_min = PERIOD_BYTES_MIN,
+       .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
        .periods_min = 2,
-       .periods_max = 16384,
+       .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_ac97_hardware = {
        .info = SNDRV_PCM_INFO_MMAP |
@@ -88,11 +98,11 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
        .rate_max = 48000,
        .channels_min = 2,
        .channels_max = 2,
-       .buffer_bytes_max = 256 * 1024,
-       .period_bytes_min = 128,
-       .period_bytes_max = 128 * 1024,
+       .buffer_bytes_max = BUFFER_BYTES_MAX,
+       .period_bytes_min = PERIOD_BYTES_MIN,
+       .period_bytes_max = BUFFER_BYTES_MAX / 2,
        .periods_min = 2,
-       .periods_max = 2048,
+       .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 
 static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = {
@@ -155,6 +165,12 @@ static int oxygen_open(struct snd_pcm_substream *substream,
                if (err < 0)
                        return err;
        }
+       if (channel == PCM_MULTICH) {
+               err = snd_pcm_hw_constraint_minmax
+                       (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000);
+               if (err < 0)
+                       return err;
+       }
        snd_pcm_set_sync(substream);
        chip->streams[channel] = substream;
 
@@ -517,6 +533,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd)
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
                pausing = 0;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -663,12 +680,14 @@ int oxygen_pcm_init(struct oxygen *chip)
                        snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
                                                      SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(chip->pci),
-                                                     512 * 1024, 2048 * 1024);
+                                                     DEFAULT_BUFFER_BYTES_MULTICH,
+                                                     BUFFER_BYTES_MAX_MULTICH);
                if (ins)
                        snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
                                                      SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(chip->pci),
-                                                     128 * 1024, 256 * 1024);
+                                                     DEFAULT_BUFFER_BYTES,
+                                                     BUFFER_BYTES_MAX);
        }
 
        outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF);
@@ -688,7 +707,8 @@ int oxygen_pcm_init(struct oxygen *chip)
                strcpy(pcm->name, "Digital");
                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(chip->pci),
-                                                     128 * 1024, 256 * 1024);
+                                                     DEFAULT_BUFFER_BYTES,
+                                                     BUFFER_BYTES_MAX);
        }
 
        if (chip->has_ac97_1) {
@@ -718,7 +738,8 @@ int oxygen_pcm_init(struct oxygen *chip)
                strcpy(pcm->name, outs ? "Front Panel" : "Analog 2");
                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(chip->pci),
-                                                     128 * 1024, 256 * 1024);
+                                                     DEFAULT_BUFFER_BYTES,
+                                                     BUFFER_BYTES_MAX);
        }
        return 0;
 }
index 7f84fa5deca2864473c00d60ff07ed602235204c..9a2c16bf94e0479ab359640808f829e1950b7d09 100644 (file)
@@ -79,7 +79,7 @@
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("Asus AVx00 driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -132,6 +132,9 @@ struct xonar_data {
        u8 ext_power_int_reg;
        u8 ext_power_bit;
        u8 has_power;
+       u8 pcm1796_oversampling;
+       u8 cs4398_fm;
+       u8 cs4362a_fm;
 };
 
 static void pcm1796_write(struct oxygen *chip, unsigned int codec,
@@ -159,6 +162,14 @@ static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
        oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
 }
 
+static void xonar_enable_output(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+
+       msleep(data->anti_pop_delay);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
 static void xonar_common_init(struct oxygen *chip)
 {
        struct xonar_data *data = chip->model_data;
@@ -170,32 +181,59 @@ static void xonar_common_init(struct oxygen *chip)
                data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
                                     & data->ext_power_bit);
        }
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_CS53x1_M_MASK | data->output_enable_bit);
        oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
                              GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
        oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
-       msleep(data->anti_pop_delay);
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit);
-       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+       xonar_enable_output(chip);
 }
 
-static void xonar_d2_init(struct oxygen *chip)
+static void update_pcm1796_volume(struct oxygen *chip)
 {
-       struct xonar_data *data = chip->model_data;
        unsigned int i;
 
-       data->anti_pop_delay = 300;
-       data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
+       for (i = 0; i < 4; ++i) {
+               pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
+               pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
+       }
+}
+
+static void update_pcm1796_mute(struct oxygen *chip)
+{
+       unsigned int i;
+       u8 value;
+
+       value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+       if (chip->dac_mute)
+               value |= PCM1796_MUTE;
+       for (i = 0; i < 4; ++i)
+               pcm1796_write(chip, i, 18, value);
+}
+
+static void pcm1796_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+       unsigned int i;
 
        for (i = 0; i < 4; ++i) {
-               pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED |
-                             PCM1796_FMT_24_LJUST | PCM1796_ATLD);
                pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
-               pcm1796_write(chip, i, 20, PCM1796_OS_64);
+               pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
                pcm1796_write(chip, i, 21, 0);
-               pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */
-               pcm1796_write(chip, i, 17, 0x0f);
        }
+       update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */
+       update_pcm1796_volume(chip);
+}
+
+static void xonar_d2_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+
+       data->anti_pop_delay = 300;
+       data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
+       data->pcm1796_oversampling = PCM1796_OS_64;
+
+       pcm1796_init(chip);
 
        oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
@@ -217,31 +255,47 @@ static void xonar_d2x_init(struct oxygen *chip)
        xonar_d2_init(chip);
 }
 
-static void xonar_dx_init(struct oxygen *chip)
+static void update_cs4362a_volumes(struct oxygen *chip)
 {
-       struct xonar_data *data = chip->model_data;
+       u8 mute;
 
-       data->anti_pop_delay = 800;
-       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
-       data->ext_power_reg = OXYGEN_GPI_DATA;
-       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
-       data->ext_power_bit = GPI_DX_EXT_POWER;
+       mute = chip->dac_mute ? CS4362A_MUTE : 0;
+       cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute);
+       cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute);
+       cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute);
+       cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute);
+       cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute);
+       cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute);
+}
 
-       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
-                      OXYGEN_2WIRE_LENGTH_8 |
-                      OXYGEN_2WIRE_INTERRUPT_MASK |
-                      OXYGEN_2WIRE_SPEED_FAST);
+static void update_cs43xx_volume(struct oxygen *chip)
+{
+       cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2);
+       cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2);
+       update_cs4362a_volumes(chip);
+}
+
+static void update_cs43xx_mute(struct oxygen *chip)
+{
+       u8 reg;
+
+       reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
+       if (chip->dac_mute)
+               reg |= CS4398_MUTE_B | CS4398_MUTE_A;
+       cs4398_write(chip, 4, reg);
+       update_cs4362a_volumes(chip);
+}
+
+static void cs43xx_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
 
        /* set CPEN (control port mode) and power down */
        cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
        cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
        /* configure */
-       cs4398_write(chip, 2, CS4398_FM_SINGLE |
-                    CS4398_DEM_NONE | CS4398_DIF_LJUST);
+       cs4398_write(chip, 2, data->cs4398_fm);
        cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
-       cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE);
-       cs4398_write(chip, 5, 0xfe);
-       cs4398_write(chip, 6, 0xfe);
        cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP |
                     CS4398_ZERO_CROSS | CS4398_SOFT_RAMP);
        cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
@@ -249,21 +303,35 @@ static void xonar_dx_init(struct oxygen *chip)
                      CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
        cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
        cs4362a_write(chip, 0x05, 0);
-       cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE |
-                     CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L);
-       cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE);
-       cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE);
-       cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE |
-                     CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L);
-       cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE);
-       cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE);
-       cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE |
-                     CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L);
-       cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE);
-       cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE);
+       cs4362a_write(chip, 0x06, data->cs4362a_fm);
+       cs4362a_write(chip, 0x09, data->cs4362a_fm);
+       cs4362a_write(chip, 0x0c, data->cs4362a_fm);
+       update_cs43xx_volume(chip);
+       update_cs43xx_mute(chip);
        /* clear power down */
        cs4398_write(chip, 8, CS4398_CPEN);
        cs4362a_write(chip, 0x01, CS4362A_CPEN);
+}
+
+static void xonar_dx_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+
+       data->anti_pop_delay = 800;
+       data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
+       data->ext_power_reg = OXYGEN_GPI_DATA;
+       data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+       data->ext_power_bit = GPI_DX_EXT_POWER;
+       data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
+       data->cs4362a_fm = CS4362A_FM_SINGLE |
+               CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+
+       oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+                      OXYGEN_2WIRE_LENGTH_8 |
+                      OXYGEN_2WIRE_INTERRUPT_MASK |
+                      OXYGEN_2WIRE_SPEED_FAST);
+
+       cs43xx_init(chip);
 
        oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
                          GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
@@ -291,37 +359,28 @@ static void xonar_dx_cleanup(struct oxygen *chip)
        oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
 }
 
-static void set_pcm1796_params(struct oxygen *chip,
-                              struct snd_pcm_hw_params *params)
+static void xonar_d2_resume(struct oxygen *chip)
 {
-       unsigned int i;
-       u8 value;
-
-       value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
-       for (i = 0; i < 4; ++i)
-               pcm1796_write(chip, i, 20, value);
+       pcm1796_init(chip);
+       xonar_enable_output(chip);
 }
 
-static void update_pcm1796_volume(struct oxygen *chip)
+static void xonar_dx_resume(struct oxygen *chip)
 {
-       unsigned int i;
-
-       for (i = 0; i < 4; ++i) {
-               pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
-               pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
-       }
+       cs43xx_init(chip);
+       xonar_enable_output(chip);
 }
 
-static void update_pcm1796_mute(struct oxygen *chip)
+static void set_pcm1796_params(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params)
 {
+       struct xonar_data *data = chip->model_data;
        unsigned int i;
-       u8 value;
 
-       value = PCM1796_FMT_24_LJUST | PCM1796_ATLD;
-       if (chip->dac_mute)
-               value |= PCM1796_MUTE;
+       data->pcm1796_oversampling =
+               params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
        for (i = 0; i < 4; ++i)
-               pcm1796_write(chip, i, 18, value);
+               pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
 }
 
 static void set_cs53x1_params(struct oxygen *chip,
@@ -342,55 +401,24 @@ static void set_cs53x1_params(struct oxygen *chip,
 static void set_cs43xx_params(struct oxygen *chip,
                              struct snd_pcm_hw_params *params)
 {
-       u8 fm_cs4398, fm_cs4362a;
+       struct xonar_data *data = chip->model_data;
 
-       fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST;
-       fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+       data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST;
+       data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
        if (params_rate(params) <= 50000) {
-               fm_cs4398 |= CS4398_FM_SINGLE;
-               fm_cs4362a |= CS4362A_FM_SINGLE;
+               data->cs4398_fm |= CS4398_FM_SINGLE;
+               data->cs4362a_fm |= CS4362A_FM_SINGLE;
        } else if (params_rate(params) <= 100000) {
-               fm_cs4398 |= CS4398_FM_DOUBLE;
-               fm_cs4362a |= CS4362A_FM_DOUBLE;
+               data->cs4398_fm |= CS4398_FM_DOUBLE;
+               data->cs4362a_fm |= CS4362A_FM_DOUBLE;
        } else {
-               fm_cs4398 |= CS4398_FM_QUAD;
-               fm_cs4362a |= CS4362A_FM_QUAD;
+               data->cs4398_fm |= CS4398_FM_QUAD;
+               data->cs4362a_fm |= CS4362A_FM_QUAD;
        }
-       cs4398_write(chip, 2, fm_cs4398);
-       cs4362a_write(chip, 0x06, fm_cs4362a);
-       cs4362a_write(chip, 0x09, fm_cs4362a);
-       cs4362a_write(chip, 0x0c, fm_cs4362a);
-}
-
-static void update_cs4362a_volumes(struct oxygen *chip)
-{
-       u8 mute;
-
-       mute = chip->dac_mute ? CS4362A_MUTE : 0;
-       cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute);
-       cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute);
-       cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute);
-       cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute);
-       cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute);
-       cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute);
-}
-
-static void update_cs43xx_volume(struct oxygen *chip)
-{
-       cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2);
-       cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2);
-       update_cs4362a_volumes(chip);
-}
-
-static void update_cs43xx_mute(struct oxygen *chip)
-{
-       u8 reg;
-
-       reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
-       if (chip->dac_mute)
-               reg |= CS4398_MUTE_B | CS4398_MUTE_A;
-       cs4398_write(chip, 4, reg);
-       update_cs4362a_volumes(chip);
+       cs4398_write(chip, 2, data->cs4398_fm);
+       cs4362a_write(chip, 0x06, data->cs4362a_fm);
+       cs4362a_write(chip, 0x09, data->cs4362a_fm);
+       cs4362a_write(chip, 0x0c, data->cs4362a_fm);
 }
 
 static void xonar_gpio_changed(struct oxygen *chip)
@@ -535,6 +563,8 @@ static const struct oxygen_model xonar_models[] = {
                .control_filter = xonar_d2_control_filter,
                .mixer_init = xonar_mixer_init,
                .cleanup = xonar_cleanup,
+               .suspend = xonar_cleanup,
+               .resume = xonar_d2_resume,
                .set_dac_params = set_pcm1796_params,
                .set_adc_params = set_cs53x1_params,
                .update_dac_volume = update_pcm1796_volume,
@@ -563,6 +593,8 @@ static const struct oxygen_model xonar_models[] = {
                .control_filter = xonar_d2_control_filter,
                .mixer_init = xonar_mixer_init,
                .cleanup = xonar_cleanup,
+               .suspend = xonar_cleanup,
+               .resume = xonar_d2_resume,
                .set_dac_params = set_pcm1796_params,
                .set_adc_params = set_cs53x1_params,
                .update_dac_volume = update_pcm1796_volume,
@@ -592,6 +624,8 @@ static const struct oxygen_model xonar_models[] = {
                .control_filter = xonar_dx_control_filter,
                .mixer_init = xonar_dx_mixer_init,
                .cleanup = xonar_dx_cleanup,
+               .suspend = xonar_dx_cleanup,
+               .resume = xonar_dx_resume,
                .set_dac_params = set_cs43xx_params,
                .set_adc_params = set_cs53x1_params,
                .update_dac_volume = update_cs43xx_volume,
@@ -636,6 +670,10 @@ static struct pci_driver xonar_driver = {
        .id_table = xonar_ids,
        .probe = xonar_probe,
        .remove = __devexit_p(oxygen_pci_remove),
+#ifdef CONFIG_PM
+       .suspend = oxygen_pci_suspend,
+       .resume = oxygen_pci_resume,
+#endif
 };
 
 static int __init alsa_card_xonar_init(void)
index 7fdcdc8c6b6478bbce2fff1c3f784ed90fb51a37..2c7e25336795d6bfb6588019069ff77947163e61 100644 (file)
@@ -516,7 +516,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        int capture_mask = 0;
        int playback_mask = 0;
 
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        struct timeval my_tv1, my_tv2;
        do_gettimeofday(&my_tv1);
 #endif
@@ -623,7 +623,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
 
        mutex_unlock(&mgr->setup_mutex);
 
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        do_gettimeofday(&my_tv2);
        snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
                    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
index 78aa81feaa4a9edfccb8fde5444b580d3afbb1a6..abe5c59b72dfbe5366c5932911408e0848a1e0ed 100644 (file)
@@ -473,7 +473,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = {
 [CMD_AUDIO_LEVEL_ADJUST] =             { 0xc22000, 0, RMH_SSIZE_FIXED },
 };
 
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
 static char* cmd_names[] = {
 [CMD_VERSION] =                                "CMD_VERSION",
 [CMD_SUPPORTED] =                      "CMD_SUPPORTED",
@@ -549,7 +549,7 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                                }
                        }
                }
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
                if (rmh->cmd_idx < CMD_LAST_INDEX)
                        snd_printdd("    stat[%d]=%x\n", i, data);
 #endif
@@ -597,7 +597,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                data |= 0x008000;       /* MASK_MORE_THAN_1_WORD_COMMAND */
        else
                data &= 0xff7fff;       /* MASK_1_WORD_COMMAND */
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        if (rmh->cmd_idx < CMD_LAST_INDEX)
                snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]);
 #endif
@@ -624,7 +624,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
                for (i=1; i < rmh->cmd_len; i++) {
                        /* send other words */
                        data = rmh->cmd[i];
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
                        if (rmh->cmd_idx < CMD_LAST_INDEX)
                                snd_printdd("    cmd[%d]=%x\n", i, data);
 #endif
@@ -847,7 +847,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m
        int state, i, err;
        int audio_mask;
 
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        struct timeval my_tv1, my_tv2;
        do_gettimeofday(&my_tv1);
 #endif
@@ -894,7 +894,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m
                if (err)
                        return err;
        }
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        do_gettimeofday(&my_tv2);
        snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n",
                    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
@@ -951,7 +951,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err,
                                  enum pcxhr_async_err_src err_src, int pipe,
                                  int is_capture)
 {
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        static char* err_src_name[] = {
                [PCXHR_ERR_PIPE]        = "Pipe",
                [PCXHR_ERR_STREAM]      = "Stream",
@@ -1169,7 +1169,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
                                    mgr->dsp_time_last, dsp_time_new);
                        mgr->dsp_time_err++;
                }
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
                if (dsp_time_diff == 0)
                        snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new);
                else if (dsp_time_diff >= (2*PCXHR_GRANULARITY))
@@ -1208,7 +1208,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
                mgr->src_it_dsp = reg;
                tasklet_hi_schedule(&mgr->msg_taskq);
        }
-#ifdef CONFIG_SND_DEBUG_DETECT
+#ifdef CONFIG_SND_DEBUG_VERBOSE
        if (reg & PCXHR_FATAL_DSP_ERR)
                snd_printdd("FATAL DSP ERROR : %x\n", reg);
 #endif
index bbcee2c09ae42e15085cc91d0bcb1625b50118dd..a69b4206c69e205f9a88726f63182f75b36491ee 100644 (file)
@@ -1590,7 +1590,10 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream,
        if (spdif_flag) {
                if (trident->device != TRIDENT_DEVICE_ID_SI7018) {
                        outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));
-                       outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
+                       val = trident->spdif_pcm_ctrl;
+                       if (!go)
+                               val &= ~(0x28);
+                       outb(val, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));
                } else {
                        outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));
                        val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN;
index df9b487fa17e7ca582e1eaae362656ca591e6620..3fd7f1b29b0f57840192aff0e4a97294134c0a5b 100644 (file)
@@ -310,181 +310,3 @@ int snd_trident_free_pages(struct snd_trident *trident,
        mutex_unlock(&hdr->block_mutex);
        return 0;
 }
-
-
-/*----------------------------------------------------------------
- * memory allocation using multiple pages (for synth)
- *----------------------------------------------------------------
- * Unlike the DMA allocation above, non-contiguous pages are
- * assigned to TLB.
- *----------------------------------------------------------------*/
-
-/*
- */
-static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk);
-static int synth_free_pages(struct snd_trident *hw, struct snd_util_memblk *blk);
-
-/*
- * allocate a synth sample area
- */
-struct snd_util_memblk *
-snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size)
-{
-       struct snd_util_memblk *blk;
-       struct snd_util_memhdr *hdr = hw->tlb.memhdr; 
-
-       mutex_lock(&hdr->block_mutex);
-       blk = __snd_util_mem_alloc(hdr, size);
-       if (blk == NULL) {
-               mutex_unlock(&hdr->block_mutex);
-               return NULL;
-       }
-       if (synth_alloc_pages(hw, blk)) {
-               __snd_util_mem_free(hdr, blk);
-               mutex_unlock(&hdr->block_mutex);
-               return NULL;
-       }
-       mutex_unlock(&hdr->block_mutex);
-       return blk;
-}
-
-EXPORT_SYMBOL(snd_trident_synth_alloc);
-
-/*
- * free a synth sample area
- */
-int
-snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk)
-{
-       struct snd_util_memhdr *hdr = hw->tlb.memhdr; 
-
-       mutex_lock(&hdr->block_mutex);
-       synth_free_pages(hw, blk);
-        __snd_util_mem_free(hdr, blk);
-       mutex_unlock(&hdr->block_mutex);
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_trident_synth_free);
-
-/*
- * reset TLB entry and free kernel page
- */
-static void clear_tlb(struct snd_trident *trident, int page)
-{
-       void *ptr = page_to_ptr(trident, page);
-       dma_addr_t addr = page_to_addr(trident, page);
-       set_silent_tlb(trident, page);
-       if (ptr) {
-               struct snd_dma_buffer dmab;
-               dmab.dev.type = SNDRV_DMA_TYPE_DEV;
-               dmab.dev.dev = snd_dma_pci_data(trident->pci);
-               dmab.area = ptr;
-               dmab.addr = addr;
-               dmab.bytes = ALIGN_PAGE_SIZE;
-               snd_dma_free_pages(&dmab);
-       }
-}
-
-/* check new allocation range */
-static void get_single_page_range(struct snd_util_memhdr *hdr,
-                                 struct snd_util_memblk *blk,
-                                 int *first_page_ret, int *last_page_ret)
-{
-       struct list_head *p;
-       struct snd_util_memblk *q;
-       int first_page, last_page;
-       first_page = firstpg(blk);
-       if ((p = blk->list.prev) != &hdr->block) {
-               q = list_entry(p, struct snd_util_memblk, list);
-               if (lastpg(q) == first_page)
-                       first_page++;  /* first page was already allocated */
-       }
-       last_page = lastpg(blk);
-       if ((p = blk->list.next) != &hdr->block) {
-               q = list_entry(p, struct snd_util_memblk, list);
-               if (firstpg(q) == last_page)
-                       last_page--; /* last page was already allocated */
-       }
-       *first_page_ret = first_page;
-       *last_page_ret = last_page;
-}
-
-/*
- * allocate kernel pages and assign them to TLB
- */
-static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk)
-{
-       int page, first_page, last_page;
-       struct snd_dma_buffer dmab;
-
-       firstpg(blk) = get_aligned_page(blk->offset);
-       lastpg(blk) = get_aligned_page(blk->offset + blk->size - 1);
-       get_single_page_range(hw->tlb.memhdr, blk, &first_page, &last_page);
-
-       /* allocate a kernel page for each Trident page -
-        * fortunately Trident page size and kernel PAGE_SIZE is identical!
-        */
-       for (page = first_page; page <= last_page; page++) {
-               if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(hw->pci),
-                                       ALIGN_PAGE_SIZE, &dmab) < 0)
-                       goto __fail;
-               if (! is_valid_page(dmab.addr)) {
-                       snd_dma_free_pages(&dmab);
-                       goto __fail;
-               }
-               set_tlb_bus(hw, page, (unsigned long)dmab.area, dmab.addr);
-       }
-       return 0;
-
-__fail:
-       /* release allocated pages */
-       last_page = page - 1;
-       for (page = first_page; page <= last_page; page++)
-               clear_tlb(hw, page);
-
-       return -ENOMEM;
-}
-
-/*
- * free pages
- */
-static int synth_free_pages(struct snd_trident *trident, struct snd_util_memblk *blk)
-{
-       int page, first_page, last_page;
-
-       get_single_page_range(trident->tlb.memhdr, blk, &first_page, &last_page);
-       for (page = first_page; page <= last_page; page++)
-               clear_tlb(trident, page);
-
-       return 0;
-}
-
-/*
- * copy_from_user(blk + offset, data, size)
- */
-int snd_trident_synth_copy_from_user(struct snd_trident *trident,
-                                    struct snd_util_memblk *blk,
-                                    int offset, const char __user *data, int size)
-{
-       int page, nextofs, end_offset, temp, temp1;
-
-       offset += blk->offset;
-       end_offset = offset + size;
-       page = get_aligned_page(offset) + 1;
-       do {
-               nextofs = aligned_page_offset(page);
-               temp = nextofs - offset;
-               temp1 = end_offset - offset;
-               if (temp1 < temp)
-                       temp = temp1;
-               if (copy_from_user(offset_ptr(trident, offset), data, temp))
-                       return -EFAULT;
-               offset = nextofs;
-               data += temp;
-               page++;
-       } while (offset < end_offset);
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_trident_synth_copy_from_user);
index b585cc3e4c472eea6434e89d9ed463038f6a61c9..6781be9e3078ac702364770f407fbc4458486882 100644 (file)
@@ -1756,6 +1756,12 @@ static struct ac97_quirk ac97_quirks[] = {
                .name = "ECS L7VMM2",
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x1019,
+               .subdevice = 0x1841,
+               .name = "ECS K7VTA3",
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x1849,
                .subdevice = 0x3059,
index 29b3056c51098b708aaa6e860af148a011bae098..7129df5f315b32d01384560e1e2b0103c0e685f9 100644 (file)
@@ -2205,6 +2205,7 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip)
        for (reg = 0x80; reg < 0xc0; reg += 4)
                snd_ymfpci_writel(chip, reg, 0);
        snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
+       snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff);
        snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff);
        snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff);
        snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
@@ -2324,6 +2325,7 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state)
                chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
        chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
        snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
+       snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
        snd_ymfpci_disable_dsp(chip);
        pci_disable_device(pci);
        pci_save_state(pci);
index c9fa1a2bc58b852e3e4680589d6c1b1b71f6145b..7fbb190adf6d1a256b59f4b0d442e9fa0a4e1011 100644 (file)
@@ -1,11 +1,16 @@
 # ALSA PCMCIA drivers
 
-menu "PCMCIA devices"
-       depends on SND!=n && PCMCIA
+menuconfig SND_PCMCIA
+       bool "PCMCIA sound devices"
+       depends on PCMCIA
+       default y
+       help
+         Support for sound devices connected via the PCMCIA bus.
+
+if SND_PCMCIA && PCMCIA
 
 config SND_VXPOCKET
        tristate "Digigram VXpocket"
-       depends on SND && PCMCIA
        select SND_VX_LIB
        help
          Say Y here to include support for Digigram VXpocket and
@@ -16,7 +21,6 @@ config SND_VXPOCKET
 
 config SND_PDAUDIOCF
        tristate "Sound Core PDAudioCF"
-       depends on SND && PCMCIA
        select SND_PCM
        help
          Say Y here to include support for Sound Core PDAudioCF
@@ -25,4 +29,5 @@ config SND_PDAUDIOCF
          To compile this driver as a module, choose M here: the module
          will be called snd-pdaudiocf.
 
-endmenu
+endif  # SND_PCMCIA
+
index 157b0b539f39d33cfc3b8f7bce35b1c288649bd6..99bf2a65a6f5ce82260b2f7d0f8fdbf56b804c7f 100644 (file)
@@ -151,7 +151,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
        unsigned int i;
        int c;
        int regCSUER, regRUER;
-       unsigned char *image;
+       const unsigned char *image;
        unsigned char data;
 
        /* Switch to programmation mode */
index cacb0b1368833d6d2055ee0bffdba03db273dec1..777de2b171781b78eca1a347238efc6a585624b5 100644 (file)
@@ -1,17 +1,17 @@
 # ALSA PowerMac drivers
 
-menu "ALSA PowerMac devices"
-       depends on SND!=n && PPC
-
-comment "ALSA PowerMac requires I2C"
-       depends on SND && I2C=n
+menuconfig SND_PPC
+       bool "PowerPC sound devices"
+       depends on PPC64 || PPC32
+       default y
+       help
+         Support for sound devices specific to PowerPC architectures.
 
-comment "ALSA PowerMac requires INPUT"
-       depends on SND && INPUT=n
+if SND_PPC
 
 config SND_POWERMAC
        tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
-       depends on SND && I2C && INPUT && PPC_PMAC
+       depends on I2C && INPUT && PPC_PMAC
        select SND_PCM
        help
          Say Y here to include support for the integrated sound device.
@@ -32,14 +32,9 @@ config SND_POWERMAC_AUTO_DRC
          Note that you can turn on/off DRC manually even without this
          option.
 
-endmenu
-
-menu "ALSA PowerPC devices"
-       depends on SND!=n && ( PPC64 || PPC32 )
-
 config SND_PS3
        tristate "PS3 Audio support"
-       depends on SND && PS3_PS3AV
+       depends on PS3_PS3AV
        select SND_PCM
        default m
        help
@@ -52,4 +47,5 @@ config SND_PS3_DEFAULT_START_DELAY
        int "Startup delay time in ms"
        depends on SND_PS3
        default "2000"
-endmenu
+
+endif  # SND_PPC
index ca9452901a50517e139f1e7784e327659b0bff48..8a5b29031933a09f1a9d1ef047ee2a1db93364c4 100644 (file)
@@ -249,9 +249,7 @@ int __init snd_pmac_daca_init(struct snd_pmac *chip)
        int i, err;
        struct pmac_daca *mix;
 
-#ifdef CONFIG_KMOD
        request_module("i2c-powermac");
-#endif /* CONFIG_KMOD */
 
        mix = kzalloc(sizeof(*mix), GFP_KERNEL);
        if (! mix)
index 3f8d7164cef9438407b3f00128739438f92069b7..009df8dd37a8483a10987b948ecd3329dd1e556c 100644 (file)
@@ -1350,9 +1350,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
        struct device_node *tas_node, *np;
        char *chipname;
 
-#ifdef CONFIG_KMOD
        request_module("i2c-powermac");
-#endif /* CONFIG_KMOD */
 
        mix = kzalloc(sizeof(*mix), GFP_KERNEL);
        if (! mix)
index b7e08ef22a940ef2d567c9c06c0d6816b8f33c1a..cfc1439858029e32956906947ecdf2755299059d 100644 (file)
@@ -1,14 +1,22 @@
 # ALSA SH drivers
 
-menu "SUPERH devices"
-       depends on SND!=n && SUPERH
+menuconfig SND_SUPERH
+       bool "SUPERH sound devices"
+       depends on SUPERH
+       default y
+       help
+         Support for sound devices specific to SUPERH architectures.
+         Drivers that are implemented on ASoC can be found in
+         "ALSA for SoC audio support" section.
+
+if SND_SUPERH
 
 config SND_AICA
        tristate "Dreamcast Yamaha AICA sound"
-       depends on SH_DREAMCAST && SND
+       depends on SH_DREAMCAST
        select SND_PCM
        help
          ALSA Sound driver for the SEGA Dreamcast console.
 
-endmenu
+endif  # SND_SUPERH
 
index 18f28ac4bfe82997733df97c1c1eaaf05dc41adb..f743530add8f2bf8a9b58a345ec515b62e3a056b 100644 (file)
@@ -2,15 +2,8 @@
 # SoC audio configuration
 #
 
-menu "System on Chip audio support"
-       depends on SND!=n
-
-config SND_SOC_AC97_BUS
-       bool
-
-config SND_SOC
+menuconfig SND_SOC
        tristate "ALSA for SoC audio support"
-       depends on SND
        select SND_PCM
        ---help---
 
@@ -23,8 +16,15 @@ config SND_SOC
          This ASoC audio support can also be built as a module.  If so, the module
          will be called snd-soc-core.
 
+if SND_SOC
+
+config SND_SOC_AC97_BUS
+       bool
+
 # All the supported Soc's
+source "sound/soc/at32/Kconfig"
 source "sound/soc/at91/Kconfig"
+source "sound/soc/au1x/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
@@ -35,4 +35,5 @@ source "sound/soc/omap/Kconfig"
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
 
-endmenu
+endif  # SND_SOC
+
index 782db2127108fd26c19a0bb6bf2ee378cbd4d0ac..933a66d30804950b96b1e185285880bf204d673f 100644 (file)
@@ -1,4 +1,5 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
-obj-$(CONFIG_SND_SOC)  += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/
+obj-$(CONFIG_SND_SOC)  += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
+obj-$(CONFIG_SND_SOC)  += omap/ au1x/
diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig
new file mode 100644 (file)
index 0000000..b0765e8
--- /dev/null
@@ -0,0 +1,34 @@
+config SND_AT32_SOC
+        tristate "SoC Audio for the Atmel AT32 System-on-a-Chip"
+        depends on AVR32 && SND_SOC
+        help
+          Say Y or M if you want to add support for codecs attached to 
+          the AT32 SSC interface.  You will also need to
+          to select the audio interfaces to support below.
+
+
+config SND_AT32_SOC_SSC
+        tristate
+
+
+
+config SND_AT32_SOC_PLAYPAQ
+        tristate "SoC Audio support for PlayPaq with WM8510"
+        depends on SND_AT32_SOC && BOARD_PLAYPAQ
+        select SND_AT32_SOC_SSC
+        select SND_SOC_WM8510
+        help
+          Say Y or M here if you want to add support for SoC audio
+          on the LRS PlayPaq.
+
+
+
+config SND_AT32_SOC_PLAYPAQ_SLAVE
+        bool "Run CODEC on PlayPaq in slave mode"
+        depends on SND_AT32_SOC_PLAYPAQ
+        default n
+        help
+          Say Y if you want to run with the AT32 SSC generating the BCLK
+          and FRAME signals on the PlayPaq.  Unless you want to play
+          with the AT32 as the SSC master, you probably want to say N here,
+          as this will give you better sound quality.
diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile
new file mode 100644 (file)
index 0000000..c03e55e
--- /dev/null
@@ -0,0 +1,11 @@
+# AT32 Platform Support
+snd-soc-at32-objs := at32-pcm.o
+snd-soc-at32-ssc-objs := at32-ssc.o
+
+obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o
+obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o
+
+# AT32 Machine Support
+snd-soc-playpaq-objs := playpaq_wm8510.o
+
+obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c
new file mode 100644 (file)
index 0000000..435f1da
--- /dev/null
@@ -0,0 +1,491 @@
+/* sound/soc/at32/at32-pcm.c
+ * ASoC PCM interface for Atmel AT32 SoC
+ *
+ * Copyright (C) 2008 Long Range Systems
+ *    Geoffrey Wossum <gwossum@acm.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.
+ *
+ * Note that this is basically a port of the sound/soc/at91-pcm.c to
+ * the AVR32 kernel.  Thanks to Frank Mandarino for that code.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "at32-pcm.h"
+
+
+
+/*--------------------------------------------------------------------------*\
+ * Hardware definition
+\*--------------------------------------------------------------------------*/
+/* TODO: These values were taken from the AT91 platform driver, check
+ *      them against real values for AT32
+ */
+static const struct snd_pcm_hardware at32_pcm_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_PAUSE),
+
+       .formats = SNDRV_PCM_FMTBIT_S16,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8192,       /* 512 frames * 16 bytes / frame */
+       .periods_min = 2,
+       .periods_max = 1024,
+       .buffer_bytes_max = 32 * 1024,
+};
+
+
+
+/*--------------------------------------------------------------------------*\
+ * Data types
+\*--------------------------------------------------------------------------*/
+struct at32_runtime_data {
+       struct at32_pcm_dma_params *params;
+       dma_addr_t dma_buffer;  /* physical address of DMA buffer */
+       dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
+       size_t period_size;
+
+       dma_addr_t period_ptr;  /* physical address of next period */
+       int periods;            /* period index of period_ptr */
+
+       /* Save PDC registers (for power management) */
+       u32 pdc_xpr_save;
+       u32 pdc_xcr_save;
+       u32 pdc_xnpr_save;
+       u32 pdc_xncr_save;
+};
+
+
+
+/*--------------------------------------------------------------------------*\
+ * Helper functions
+\*--------------------------------------------------------------------------*/
+static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *dmabuf = &substream->dma_buffer;
+       size_t size = at32_pcm_hardware.buffer_bytes_max;
+
+       dmabuf->dev.type = SNDRV_DMA_TYPE_DEV;
+       dmabuf->dev.dev = pcm->card->dev;
+       dmabuf->private_data = NULL;
+       dmabuf->area = dma_alloc_coherent(pcm->card->dev, size,
+                                         &dmabuf->addr, GFP_KERNEL);
+       pr_debug("at32_pcm: preallocate_dma_buffer: "
+                "area=%p, addr=%p, size=%ld\n",
+                (void *)dmabuf->area, (void *)dmabuf->addr, size);
+
+       if (!dmabuf->area)
+               return -ENOMEM;
+
+       dmabuf->bytes = size;
+       return 0;
+}
+
+
+
+/*--------------------------------------------------------------------------*\
+ * ISR
+\*--------------------------------------------------------------------------*/
+static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *rtd = substream->runtime;
+       struct at32_runtime_data *prtd = rtd->private_data;
+       struct at32_pcm_dma_params *params = prtd->params;
+       static int count;
+
+       count++;
+       if (ssc_sr & params->mask->ssc_endbuf) {
+               pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
+                          substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                          "underrun" : "overrun", params->name, ssc_sr, count);
+
+               /* re-start the PDC */
+               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                          params->mask->pdc_disable);
+               prtd->period_ptr += prtd->period_size;
+               if (prtd->period_ptr >= prtd->dma_buffer_end)
+                       prtd->period_ptr = prtd->dma_buffer;
+
+
+               ssc_writex(params->ssc->regs, params->pdc->xpr,
+                          prtd->period_ptr);
+               ssc_writex(params->ssc->regs, params->pdc->xcr,
+                          prtd->period_size / params->pdc_xfer_size);
+               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                          params->mask->pdc_enable);
+       }
+
+
+       if (ssc_sr & params->mask->ssc_endx) {
+               /* Load the PDC next pointer and counter registers */
+               prtd->period_ptr += prtd->period_size;
+               if (prtd->period_ptr >= prtd->dma_buffer_end)
+                       prtd->period_ptr = prtd->dma_buffer;
+               ssc_writex(params->ssc->regs, params->pdc->xnpr,
+                          prtd->period_ptr);
+               ssc_writex(params->ssc->regs, params->pdc->xncr,
+                          prtd->period_size / params->pdc_xfer_size);
+       }
+
+
+       snd_pcm_period_elapsed(substream);
+}
+
+
+
+/*--------------------------------------------------------------------------*\
+ * PCM operations
+\*--------------------------------------------------------------------------*/
+static int at32_pcm_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct at32_runtime_data *prtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       /* this may get called several times by oss emulation
+        * with different params
+        */
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       runtime->dma_bytes = params_buffer_bytes(params);
+
+       prtd->params = rtd->dai->cpu_dai->dma_data;
+       prtd->params->dma_intr_handler = at32_pcm_dma_irq;
+
+       prtd->dma_buffer = runtime->dma_addr;
+       prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
+       prtd->period_size = params_period_bytes(params);
+
+       pr_debug("hw_params: DMA for %s initialized "
+                "(dma_bytes=%ld, period_size=%ld)\n",
+                prtd->params->name, runtime->dma_bytes, prtd->period_size);
+
+       return 0;
+}
+
+
+
+static int at32_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct at32_runtime_data *prtd = substream->runtime->private_data;
+       struct at32_pcm_dma_params *params = prtd->params;
+
+       if (params != NULL) {
+               ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
+                          params->mask->pdc_disable);
+               prtd->params->dma_intr_handler = NULL;
+       }
+
+       return 0;
+}
+
+
+
+static int at32_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct at32_runtime_data *prtd = substream->runtime->private_data;
+       struct at32_pcm_dma_params *params = prtd->params;
+
+       ssc_writex(params->ssc->regs, SSC_IDR,
+                  params->mask->ssc_endx | params->mask->ssc_endbuf);
+       ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                  params->mask->pdc_disable);
+
+       return 0;
+}
+
+
+static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *rtd = substream->runtime;
+       struct at32_runtime_data *prtd = rtd->private_data;
+       struct at32_pcm_dma_params *params = prtd->params;
+       int ret = 0;
+
+       pr_debug("at32_pcm_trigger: buffer_size = %ld, "
+                "dma_area = %p, dma_bytes = %ld\n",
+                rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               prtd->period_ptr = prtd->dma_buffer;
+
+               ssc_writex(params->ssc->regs, params->pdc->xpr,
+                          prtd->period_ptr);
+               ssc_writex(params->ssc->regs, params->pdc->xcr,
+                          prtd->period_size / params->pdc_xfer_size);
+
+               prtd->period_ptr += prtd->period_size;
+               ssc_writex(params->ssc->regs, params->pdc->xnpr,
+                          prtd->period_ptr);
+               ssc_writex(params->ssc->regs, params->pdc->xncr,
+                          prtd->period_size / params->pdc_xfer_size);
+
+               pr_debug("trigger: period_ptr=%lx, xpr=%x, "
+                        "xcr=%d, xnpr=%x, xncr=%d\n",
+                        (unsigned long)prtd->period_ptr,
+                        ssc_readx(params->ssc->regs, params->pdc->xpr),
+                        ssc_readx(params->ssc->regs, params->pdc->xcr),
+                        ssc_readx(params->ssc->regs, params->pdc->xnpr),
+                        ssc_readx(params->ssc->regs, params->pdc->xncr));
+
+               ssc_writex(params->ssc->regs, SSC_IER,
+                          params->mask->ssc_endx | params->mask->ssc_endbuf);
+               ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
+                          params->mask->pdc_enable);
+
+               pr_debug("sr=%x, imr=%x\n",
+                        ssc_readx(params->ssc->regs, SSC_SR),
+                        ssc_readx(params->ssc->regs, SSC_IER));
+               break;          /* SNDRV_PCM_TRIGGER_START */
+
+
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                          params->mask->pdc_disable);
+               break;
+
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+                          params->mask->pdc_enable);
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+
+
+static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct at32_runtime_data *prtd = runtime->private_data;
+       struct at32_pcm_dma_params *params = prtd->params;
+       dma_addr_t ptr;
+       snd_pcm_uframes_t x;
+
+       ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
+       x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
+
+       if (x == runtime->buffer_size)
+               x = 0;
+
+       return x;
+}
+
+
+
+static int at32_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct at32_runtime_data *prtd;
+       int ret = 0;
+
+       snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware);
+
+       /* ensure that buffer size is a multiple of period size */
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               goto out;
+
+       prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+       if (prtd == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       runtime->private_data = prtd;
+
+
+out:
+       return ret;
+}
+
+
+
+static int at32_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct at32_runtime_data *prtd = substream->runtime->private_data;
+
+       kfree(prtd);
+       return 0;
+}
+
+
+static int at32_pcm_mmap(struct snd_pcm_substream *substream,
+                        struct vm_area_struct *vma)
+{
+       return remap_pfn_range(vma, vma->vm_start,
+                              substream->dma_buffer.addr >> PAGE_SHIFT,
+                              vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+
+
+static struct snd_pcm_ops at32_pcm_ops = {
+       .open = at32_pcm_open,
+       .close = at32_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = at32_pcm_hw_params,
+       .hw_free = at32_pcm_hw_free,
+       .prepare = at32_pcm_prepare,
+       .trigger = at32_pcm_trigger,
+       .pointer = at32_pcm_pointer,
+       .mmap = at32_pcm_mmap,
+};
+
+
+
+/*--------------------------------------------------------------------------*\
+ * ASoC platform driver
+\*--------------------------------------------------------------------------*/
+static u64 at32_pcm_dmamask = 0xffffffff;
+
+static int at32_pcm_new(struct snd_card *card,
+                       struct snd_soc_dai *dai,
+                       struct snd_pcm *pcm)
+{
+       int ret = 0;
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &at32_pcm_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = 0xffffffff;
+
+       if (dai->playback.channels_min) {
+               ret = at32_pcm_preallocate_dma_buffer(
+                         pcm, SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (dai->capture.channels_min) {
+               pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n");
+               ret = at32_pcm_preallocate_dma_buffer(
+                         pcm, SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+
+
+out:
+       return ret;
+}
+
+
+
+static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (substream == NULL)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+               dma_free_coherent(pcm->card->dev, buf->bytes,
+                                 buf->area, buf->addr);
+               buf->area = NULL;
+       }
+}
+
+
+
+#ifdef CONFIG_PM
+static int at32_pcm_suspend(struct platform_device *pdev,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = dai->runtime;
+       struct at32_runtime_data *prtd;
+       struct at32_pcm_dma_params *params;
+
+       if (runtime == NULL)
+               return 0;
+       prtd = runtime->private_data;
+       params = prtd->params;
+
+       /* Disable the PDC and save the PDC registers */
+       ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
+
+       prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
+       prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
+       prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
+       prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
+
+       return 0;
+}
+
+
+
+static int at32_pcm_resume(struct platform_device *pdev,
+                          struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = dai->runtime;
+       struct at32_runtime_data *prtd;
+       struct at32_pcm_dma_params *params;
+
+       if (runtime == NULL)
+               return 0;
+       prtd = runtime->private_data;
+       params = prtd->params;
+
+       /* Restore the PDC registers and enable the PDC */
+       ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
+       ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
+       ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
+       ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
+
+       ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
+       return 0;
+}
+#else /* CONFIG_PM */
+#  define at32_pcm_suspend     NULL
+#  define at32_pcm_resume      NULL
+#endif /* CONFIG_PM */
+
+
+
+struct snd_soc_platform at32_soc_platform = {
+       .name = "at32-audio",
+       .pcm_ops = &at32_pcm_ops,
+       .pcm_new = at32_pcm_new,
+       .pcm_free = at32_pcm_free_dma_buffers,
+       .suspend = at32_pcm_suspend,
+       .resume = at32_pcm_resume,
+};
+EXPORT_SYMBOL_GPL(at32_soc_platform);
+
+
+
+MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
+MODULE_DESCRIPTION("Atmel AT32 PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h
new file mode 100644 (file)
index 0000000..2a52430
--- /dev/null
@@ -0,0 +1,79 @@
+/* sound/soc/at32/at32-pcm.h
+ * ASoC PCM interface for Atmel AT32 SoC
+ *
+ * Copyright (C) 2008 Long Range Systems
+ *    Geoffrey Wossum <gwossum@acm.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.
+ */
+
+#ifndef __SOUND_SOC_AT32_AT32_PCM_H
+#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__
+
+#include <linux/atmel-ssc.h>
+
+
+/*
+ * Registers and status bits that are required by the PCM driver
+ * TODO: Is ptcr really used?
+ */
+struct at32_pdc_regs {
+       u32 xpr;                /* PDC RX/TX pointer */
+       u32 xcr;                /* PDC RX/TX counter */
+       u32 xnpr;               /* PDC next RX/TX pointer */
+       u32 xncr;               /* PDC next RX/TX counter */
+       u32 ptcr;               /* PDC transfer control */
+};
+
+
+
+/*
+ * SSC mask info
+ */
+struct at32_ssc_mask {
+       u32 ssc_enable;         /* SSC RX/TX enable */
+       u32 ssc_disable;        /* SSC RX/TX disable */
+       u32 ssc_endx;           /* SSC ENDTX or ENDRX */
+       u32 ssc_endbuf;         /* SSC TXBUFF or RXBUFF */
+       u32 pdc_enable;         /* PDC RX/TX enable */
+       u32 pdc_disable;        /* PDC RX/TX disable */
+};
+
+
+
+/*
+ * This structure, shared between the PCM driver and the interface,
+ * contains all information required by the PCM driver to perform the
+ * PDC DMA operation.  All fields except dma_intr_handler() are initialized
+ * by the interface.  The dms_intr_handler() pointer is set by the PCM
+ * driver and called by the interface SSC interrupt handler if it is
+ * non-NULL.
+ */
+struct at32_pcm_dma_params {
+       char *name;             /* stream identifier */
+       int pdc_xfer_size;      /* PDC counter increment in bytes */
+       struct ssc_device *ssc; /* SSC device for stream */
+       struct at32_pdc_regs *pdc;      /* PDC register info */
+       struct at32_ssc_mask *mask;     /* SSC mask info */
+       struct snd_pcm_substream *substream;
+       void (*dma_intr_handler) (u32, struct snd_pcm_substream *);
+};
+
+
+
+/*
+ * The AT32 ASoC platform driver
+ */
+extern struct snd_soc_platform at32_soc_platform;
+
+
+
+/*
+ * SSC register access (since ssc_writel() / ssc_readl() require literal name)
+ */
+#define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
+#define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
+
+#endif /* __SOUND_SOC_AT32_AT32_PCM_H */
diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c
new file mode 100644 (file)
index 0000000..4ef6492
--- /dev/null
@@ -0,0 +1,849 @@
+/* sound/soc/at32/at32-ssc.c
+ * ASoC platform driver for AT32 using SSC as DAI
+ *
+ * Copyright (C) 2008 Long Range Systems
+ *    Geoffrey Wossum <gwossum@acm.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.
+ *
+ * Note that this is basically a port of the sound/soc/at91-ssc.c to
+ * the AVR32 kernel.  Thanks to Frank Mandarino for that code.
+ */
+
+/* #define DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/atmel_pdc.h>
+#include <linux/atmel-ssc.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "at32-pcm.h"
+#include "at32-ssc.h"
+
+
+
+/*-------------------------------------------------------------------------*\
+ * Constants
+\*-------------------------------------------------------------------------*/
+#define NUM_SSC_DEVICES                3
+
+/*
+ * SSC direction masks
+ */
+#define SSC_DIR_MASK_UNUSED    0
+#define SSC_DIR_MASK_PLAYBACK  1
+#define SSC_DIR_MASK_CAPTURE   2
+
+/*
+ * SSC register values that Atmel left out of <linux/atmel-ssc.h>.  These
+ * are expected to be used with SSC_BF
+ */
+/* START bit field values */
+#define SSC_START_CONTINUOUS   0
+#define SSC_START_TX_RX                1
+#define SSC_START_LOW_RF       2
+#define SSC_START_HIGH_RF      3
+#define SSC_START_FALLING_RF   4
+#define SSC_START_RISING_RF    5
+#define SSC_START_LEVEL_RF     6
+#define SSC_START_EDGE_RF      7
+#define SSS_START_COMPARE_0    8
+
+/* CKI bit field values */
+#define SSC_CKI_FALLING                0
+#define SSC_CKI_RISING         1
+
+/* CKO bit field values */
+#define SSC_CKO_NONE           0
+#define SSC_CKO_CONTINUOUS     1
+#define SSC_CKO_TRANSFER       2
+
+/* CKS bit field values */
+#define SSC_CKS_DIV            0
+#define SSC_CKS_CLOCK          1
+#define SSC_CKS_PIN            2
+
+/* FSEDGE bit field values */
+#define SSC_FSEDGE_POSITIVE    0
+#define SSC_FSEDGE_NEGATIVE    1
+
+/* FSOS bit field values */
+#define SSC_FSOS_NONE          0
+#define SSC_FSOS_NEGATIVE      1
+#define SSC_FSOS_POSITIVE      2
+#define SSC_FSOS_LOW           3
+#define SSC_FSOS_HIGH          4
+#define SSC_FSOS_TOGGLE                5
+
+#define START_DELAY            1
+
+
+
+/*-------------------------------------------------------------------------*\
+ * Module data
+\*-------------------------------------------------------------------------*/
+/*
+ * SSC PDC registered required by the PCM DMA engine
+ */
+static struct at32_pdc_regs pdc_tx_reg = {
+       .xpr = SSC_PDC_TPR,
+       .xcr = SSC_PDC_TCR,
+       .xnpr = SSC_PDC_TNPR,
+       .xncr = SSC_PDC_TNCR,
+};
+
+
+
+static struct at32_pdc_regs pdc_rx_reg = {
+       .xpr = SSC_PDC_RPR,
+       .xcr = SSC_PDC_RCR,
+       .xnpr = SSC_PDC_RNPR,
+       .xncr = SSC_PDC_RNCR,
+};
+
+
+
+/*
+ * SSC and PDC status bits for transmit and receive
+ */
+static struct at32_ssc_mask ssc_tx_mask = {
+       .ssc_enable = SSC_BIT(CR_TXEN),
+       .ssc_disable = SSC_BIT(CR_TXDIS),
+       .ssc_endx = SSC_BIT(SR_ENDTX),
+       .ssc_endbuf = SSC_BIT(SR_TXBUFE),
+       .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN),
+       .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS),
+};
+
+
+
+static struct at32_ssc_mask ssc_rx_mask = {
+       .ssc_enable = SSC_BIT(CR_RXEN),
+       .ssc_disable = SSC_BIT(CR_RXDIS),
+       .ssc_endx = SSC_BIT(SR_ENDRX),
+       .ssc_endbuf = SSC_BIT(SR_RXBUFF),
+       .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN),
+       .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS),
+};
+
+
+
+/*
+ * DMA parameters for each SSC
+ */
+static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
+       {
+        {
+         .name = "SSC0 PCM out",
+         .pdc = &pdc_tx_reg,
+         .mask = &ssc_tx_mask,
+         },
+        {
+         .name = "SSC0 PCM in",
+         .pdc = &pdc_rx_reg,
+         .mask = &ssc_rx_mask,
+         },
+        },
+       {
+        {
+         .name = "SSC1 PCM out",
+         .pdc = &pdc_tx_reg,
+         .mask = &ssc_tx_mask,
+         },
+        {
+         .name = "SSC1 PCM in",
+         .pdc = &pdc_rx_reg,
+         .mask = &ssc_rx_mask,
+         },
+        },
+       {
+        {
+         .name = "SSC2 PCM out",
+         .pdc = &pdc_tx_reg,
+         .mask = &ssc_tx_mask,
+         },
+        {
+         .name = "SSC2 PCM in",
+         .pdc = &pdc_rx_reg,
+         .mask = &ssc_rx_mask,
+         },
+        },
+};
+
+
+
+static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = {
+       {
+        .name = "ssc0",
+        .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
+        .dir_mask = SSC_DIR_MASK_UNUSED,
+        .initialized = 0,
+        },
+       {
+        .name = "ssc1",
+        .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
+        .dir_mask = SSC_DIR_MASK_UNUSED,
+        .initialized = 0,
+        },
+       {
+        .name = "ssc2",
+        .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
+        .dir_mask = SSC_DIR_MASK_UNUSED,
+        .initialized = 0,
+        },
+};
+
+
+
+
+/*-------------------------------------------------------------------------*\
+ * ISR
+\*-------------------------------------------------------------------------*/
+/*
+ * SSC interrupt handler.  Passes PDC interrupts to the DMA interrupt
+ * handler in the PCM driver.
+ */
+static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id)
+{
+       struct at32_ssc_info *ssc_p = dev_id;
+       struct at32_pcm_dma_params *dma_params;
+       u32 ssc_sr;
+       u32 ssc_substream_mask;
+       int i;
+
+       ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) &
+                 ssc_readl(ssc_p->ssc->regs, IMR));
+
+       /*
+        * Loop through substreams attached to this SSC.  If a DMA-related
+        * interrupt occured on that substream, call the DMA interrupt
+        * handler function, if one has been registered in the dma_param
+        * structure by the PCM driver.
+        */
+       for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
+               dma_params = ssc_p->dma_params[i];
+
+               if ((dma_params != NULL) &&
+                   (dma_params->dma_intr_handler != NULL)) {
+                       ssc_substream_mask = (dma_params->mask->ssc_endx |
+                                             dma_params->mask->ssc_endbuf);
+                       if (ssc_sr & ssc_substream_mask) {
+                               dma_params->dma_intr_handler(ssc_sr,
+                                                            dma_params->
+                                                            substream);
+                       }
+               }
+       }
+
+
+       return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*\
+ * DAI functions
+\*-------------------------------------------------------------------------*/
+/*
+ * Startup.  Only that one substream allowed in each direction.
+ */
+static int at32_ssc_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       int dir_mask;
+
+       dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                   SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE);
+
+       spin_lock_irq(&ssc_p->lock);
+       if (ssc_p->dir_mask & dir_mask) {
+               spin_unlock_irq(&ssc_p->lock);
+               return -EBUSY;
+       }
+       ssc_p->dir_mask |= dir_mask;
+       spin_unlock_irq(&ssc_p->lock);
+
+       return 0;
+}
+
+
+
+/*
+ * Shutdown.  Clear DMA parameters and shutdown the SSC if there
+ * are no other substreams open.
+ */
+static void at32_ssc_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct at32_pcm_dma_params *dma_params;
+       int dir_mask;
+
+       dma_params = ssc_p->dma_params[substream->stream];
+
+       if (dma_params != NULL) {
+               ssc_writel(dma_params->ssc->regs, CR,
+                          dma_params->mask->ssc_disable);
+               pr_debug("%s disabled SSC_SR=0x%08x\n",
+                        (substream->stream ? "receiver" : "transmit"),
+                        ssc_readl(ssc_p->ssc->regs, SR));
+
+               dma_params->ssc = NULL;
+               dma_params->substream = NULL;
+               ssc_p->dma_params[substream->stream] = NULL;
+       }
+
+
+       dir_mask = 1 << substream->stream;
+       spin_lock_irq(&ssc_p->lock);
+       ssc_p->dir_mask &= ~dir_mask;
+       if (!ssc_p->dir_mask) {
+               /* Shutdown the SSC clock */
+               pr_debug("at32-ssc: Stopping user %d clock\n",
+                        ssc_p->ssc->user);
+               clk_disable(ssc_p->ssc->clk);
+
+               if (ssc_p->initialized) {
+                       free_irq(ssc_p->ssc->irq, ssc_p);
+                       ssc_p->initialized = 0;
+               }
+
+               /* Reset the SSC */
+               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
+               /* clear the SSC dividers */
+               ssc_p->cmr_div = 0;
+               ssc_p->tcmr_period = 0;
+               ssc_p->rcmr_period = 0;
+       }
+       spin_unlock_irq(&ssc_p->lock);
+}
+
+
+
+/*
+ * Set the SSC system clock rate
+ */
+static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+                                  int clk_id, unsigned int freq, int dir)
+{
+       /* TODO: What the heck do I do here? */
+       return 0;
+}
+
+
+
+/*
+ * Record DAI format for use by hw_params()
+ */
+static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+                               unsigned int fmt)
+{
+       struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+       ssc_p->daifmt = fmt;
+       return 0;
+}
+
+
+
+/*
+ * Record SSC clock dividers for use in hw_params()
+ */
+static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+                                  int div_id, int div)
+{
+       struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+       switch (div_id) {
+       case AT32_SSC_CMR_DIV:
+               /*
+                * The same master clock divider is used for both
+                * transmit and receive, so if a value has already
+                * been set, it must match this value
+                */
+               if (ssc_p->cmr_div == 0)
+                       ssc_p->cmr_div = div;
+               else if (div != ssc_p->cmr_div)
+                       return -EBUSY;
+               break;
+
+       case AT32_SSC_TCMR_PERIOD:
+               ssc_p->tcmr_period = div;
+               break;
+
+       case AT32_SSC_RCMR_PERIOD:
+               ssc_p->rcmr_period = div;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+
+/*
+ * Configure the SSC
+ */
+static int at32_ssc_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       int id = rtd->dai->cpu_dai->id;
+       struct at32_ssc_info *ssc_p = &ssc_info[id];
+       struct at32_pcm_dma_params *dma_params;
+       int channels, bits;
+       u32 tfmr, rfmr, tcmr, rcmr;
+       int start_event;
+       int ret;
+
+
+       /*
+        * Currently, there is only one set of dma_params for each direction.
+        * If more are added, this code will have to be changed to select
+        * the proper set
+        */
+       dma_params = &ssc_dma_params[id][substream->stream];
+       dma_params->ssc = ssc_p->ssc;
+       dma_params->substream = substream;
+
+       ssc_p->dma_params[substream->stream] = dma_params;
+
+
+       /*
+        * The cpu_dai->dma_data field is only used to communicate the
+        * appropriate DMA parameters to the PCM driver's hw_params()
+        * function.  It should not be used for other purposes as it
+        * is common to all substreams.
+        */
+       rtd->dai->cpu_dai->dma_data = dma_params;
+
+       channels = params_channels(params);
+
+
+       /*
+        * Determine sample size in bits and the PDC increment
+        */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               bits = 8;
+               dma_params->pdc_xfer_size = 1;
+               break;
+
+       case SNDRV_PCM_FORMAT_S16:
+               bits = 16;
+               dma_params->pdc_xfer_size = 2;
+               break;
+
+       case SNDRV_PCM_FORMAT_S24:
+               bits = 24;
+               dma_params->pdc_xfer_size = 4;
+               break;
+
+       case SNDRV_PCM_FORMAT_S32:
+               bits = 32;
+               dma_params->pdc_xfer_size = 4;
+               break;
+
+       default:
+               pr_warning("at32-ssc: Unsupported PCM format %d",
+                          params_format(params));
+               return -EINVAL;
+       }
+       pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n",
+                bits, dma_params->pdc_xfer_size, channels);
+
+
+       /*
+        * The SSC only supports up to 16-bit samples in I2S format, due
+        * to the size of the Frame Mode Register FSLEN field.
+        */
+       if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
+               if (bits > 16) {
+                       pr_warning("at32-ssc: "
+                                  "sample size %d is too large for I2S\n",
+                                  bits);
+                       return -EINVAL;
+               }
+
+
+       /*
+        * Compute the SSC register settings
+        */
+       switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+                                SND_SOC_DAIFMT_MASTER_MASK)) {
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+               /*
+                * I2S format, SSC provides BCLK and LRS clocks.
+                *
+                * The SSC transmit and receive clocks are generated from the
+                * MCK divider, and the BCLK signal is output on the SSC TK line
+                */
+               pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n");
+               rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
+                       SSC_BF(RCMR_STTDLY, START_DELAY) |
+                       SSC_BF(RCMR_START, SSC_START_FALLING_RF) |
+                       SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
+                       SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
+                       SSC_BF(RCMR_CKS, SSC_CKS_DIV));
+
+               rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
+                       SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) |
+                       SSC_BF(RFMR_FSLEN, bits - 1) |
+                       SSC_BF(RFMR_DATNB, channels - 1) |
+                       SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
+
+               tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) |
+                       SSC_BF(TCMR_STTDLY, START_DELAY) |
+                       SSC_BF(TCMR_START, SSC_START_FALLING_RF) |
+                       SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
+                       SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
+                       SSC_BF(TCMR_CKS, SSC_CKS_DIV));
+
+               tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
+                       SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) |
+                       SSC_BF(TFMR_FSLEN, bits - 1) |
+                       SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) |
+                       SSC_BF(TFMR_DATLEN, bits - 1));
+               break;
+
+
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+               /*
+                * I2S format, CODEC supplies BCLK and LRC clock.
+                *
+                * The SSC transmit clock is obtained from the BCLK signal
+                * on the TK line, and the SSC receive clock is generated from
+                * the transmit clock.
+                *
+                * For single channel data, one sample is transferred on the
+                * falling edge of the LRC clock.  For two channel data, one
+                * sample is transferred on both edges of the LRC clock.
+                */
+               pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n");
+               start_event = ((channels == 1) ?
+                              SSC_START_FALLING_RF : SSC_START_EDGE_RF);
+
+               rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) |
+                       SSC_BF(RCMR_START, start_event) |
+                       SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
+                       SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
+                       SSC_BF(RCMR_CKS, SSC_CKS_CLOCK));
+
+               rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
+                       SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
+                       SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
+
+               tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) |
+                       SSC_BF(TCMR_START, start_event) |
+                       SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
+                       SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
+                       SSC_BF(TCMR_CKS, SSC_CKS_PIN));
+
+               tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
+                       SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) |
+                       SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1));
+               break;
+
+
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+               /*
+                * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
+                *
+                * The SSC transmit and receive clocks are generated from the
+                * MCK divider, and the BCLK signal is output on the SSC TK line
+                */
+               pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n");
+               rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
+                       SSC_BF(RCMR_STTDLY, 1) |
+                       SSC_BF(RCMR_START, SSC_START_RISING_RF) |
+                       SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
+                       SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
+                       SSC_BF(RCMR_CKS, SSC_CKS_DIV));
+
+               rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
+                       SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) |
+                       SSC_BF(RFMR_DATNB, channels - 1) |
+                       SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1));
+
+               tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) |
+                       SSC_BF(TCMR_STTDLY, 1) |
+                       SSC_BF(TCMR_START, SSC_START_RISING_RF) |
+                       SSC_BF(TCMR_CKI, SSC_CKI_RISING) |
+                       SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) |
+                       SSC_BF(TCMR_CKS, SSC_CKS_DIV));
+
+               tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
+                       SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) |
+                       SSC_BF(TFMR_DATNB, channels - 1) |
+                       SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1));
+               break;
+
+
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+       default:
+               pr_warning("at32-ssc: unsupported DAI format 0x%x\n",
+                          ssc_p->daifmt);
+               return -EINVAL;
+               break;
+       }
+       pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
+                rcmr, rfmr, tcmr, tfmr);
+
+
+       if (!ssc_p->initialized) {
+               /* enable peripheral clock */
+               pr_debug("at32-ssc: Starting clock\n");
+               clk_enable(ssc_p->ssc->clk);
+
+               /* Reset the SSC and its PDC registers */
+               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
+               ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+               ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+               ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+
+               ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0,
+                                 ssc_p->name, ssc_p);
+               if (ret < 0) {
+                       pr_warning("at32-ssc: request irq failed (%d)\n", ret);
+                       pr_debug("at32-ssc: Stopping clock\n");
+                       clk_disable(ssc_p->ssc->clk);
+                       return ret;
+               }
+
+               ssc_p->initialized = 1;
+       }
+
+       /* Set SSC clock mode register */
+       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
+
+       /* set receive clock mode and format */
+       ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
+       ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);
+
+       /* set transmit clock mode and format */
+       ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);
+       ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);
+
+       pr_debug("at32-ssc: SSC initialized\n");
+       return 0;
+}
+
+
+
+static int at32_ssc_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct at32_pcm_dma_params *dma_params;
+
+       dma_params = ssc_p->dma_params[substream->stream];
+
+       ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable);
+
+       return 0;
+}
+
+
+
+#ifdef CONFIG_PM
+static int at32_ssc_suspend(struct platform_device *pdev,
+                           struct snd_soc_dai *cpu_dai)
+{
+       struct at32_ssc_info *ssc_p;
+
+       if (!cpu_dai->active)
+               return 0;
+
+       ssc_p = &ssc_info[cpu_dai->id];
+
+       /* Save the status register before disabling transmit and receive */
+       ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
+       ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));
+
+       /* Save the current interrupt mask, then disable unmasked interrupts */
+       ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);
+       ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);
+
+       ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);
+       ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);
+       ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);
+       ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
+       ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
+
+       return 0;
+}
+
+
+
+static int at32_ssc_resume(struct platform_device *pdev,
+                          struct snd_soc_dai *cpu_dai)
+{
+       struct at32_ssc_info *ssc_p;
+       u32 cr;
+
+       if (!cpu_dai->active)
+               return 0;
+
+       ssc_p = &ssc_info[cpu_dai->id];
+
+       /* restore SSC register settings */
+       ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
+       ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
+       ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);
+       ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);
+       ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);
+
+       /* re-enable interrupts */
+       ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);
+
+       /* Re-enable recieve and transmit as appropriate */
+       cr = 0;
+       cr |=
+           (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;
+       cr |=
+           (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;
+       ssc_writel(ssc_p->ssc->regs, CR, cr);
+
+       return 0;
+}
+#else /* CONFIG_PM */
+#  define at32_ssc_suspend     NULL
+#  define at32_ssc_resume      NULL
+#endif /* CONFIG_PM */
+
+
+#define AT32_SSC_RATES \
+    (SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+     SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+
+#define AT32_SSC_FORMATS \
+    (SNDRV_PCM_FMTBIT_S8  | SNDRV_PCM_FMTBIT_S16 | \
+     SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32)
+
+
+struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = {
+       {
+        .name = "at32-ssc0",
+        .id = 0,
+        .type = SND_SOC_DAI_PCM,
+        .suspend = at32_ssc_suspend,
+        .resume = at32_ssc_resume,
+        .playback = {
+                     .channels_min = 1,
+                     .channels_max = 2,
+                     .rates = AT32_SSC_RATES,
+                     .formats = AT32_SSC_FORMATS,
+                     },
+        .capture = {
+                    .channels_min = 1,
+                    .channels_max = 2,
+                    .rates = AT32_SSC_RATES,
+                    .formats = AT32_SSC_FORMATS,
+                    },
+        .ops = {
+                .startup = at32_ssc_startup,
+                .shutdown = at32_ssc_shutdown,
+                .prepare = at32_ssc_prepare,
+                .hw_params = at32_ssc_hw_params,
+                },
+        .dai_ops = {
+                    .set_sysclk = at32_ssc_set_dai_sysclk,
+                    .set_fmt = at32_ssc_set_dai_fmt,
+                    .set_clkdiv = at32_ssc_set_dai_clkdiv,
+                    },
+        .private_data = &ssc_info[0],
+        },
+       {
+        .name = "at32-ssc1",
+        .id = 1,
+        .type = SND_SOC_DAI_PCM,
+        .suspend = at32_ssc_suspend,
+        .resume = at32_ssc_resume,
+        .playback = {
+                     .channels_min = 1,
+                     .channels_max = 2,
+                     .rates = AT32_SSC_RATES,
+                     .formats = AT32_SSC_FORMATS,
+                     },
+        .capture = {
+                    .channels_min = 1,
+                    .channels_max = 2,
+                    .rates = AT32_SSC_RATES,
+                    .formats = AT32_SSC_FORMATS,
+                    },
+        .ops = {
+                .startup = at32_ssc_startup,
+                .shutdown = at32_ssc_shutdown,
+                .prepare = at32_ssc_prepare,
+                .hw_params = at32_ssc_hw_params,
+                },
+        .dai_ops = {
+                    .set_sysclk = at32_ssc_set_dai_sysclk,
+                    .set_fmt = at32_ssc_set_dai_fmt,
+                    .set_clkdiv = at32_ssc_set_dai_clkdiv,
+                    },
+        .private_data = &ssc_info[1],
+        },
+       {
+        .name = "at32-ssc2",
+        .id = 2,
+        .type = SND_SOC_DAI_PCM,
+        .suspend = at32_ssc_suspend,
+        .resume = at32_ssc_resume,
+        .playback = {
+                     .channels_min = 1,
+                     .channels_max = 2,
+                     .rates = AT32_SSC_RATES,
+                     .formats = AT32_SSC_FORMATS,
+                     },
+        .capture = {
+                    .channels_min = 1,
+                    .channels_max = 2,
+                    .rates = AT32_SSC_RATES,
+                    .formats = AT32_SSC_FORMATS,
+                    },
+        .ops = {
+                .startup = at32_ssc_startup,
+                .shutdown = at32_ssc_shutdown,
+                .prepare = at32_ssc_prepare,
+                .hw_params = at32_ssc_hw_params,
+                },
+        .dai_ops = {
+                    .set_sysclk = at32_ssc_set_dai_sysclk,
+                    .set_fmt = at32_ssc_set_dai_fmt,
+                    .set_clkdiv = at32_ssc_set_dai_clkdiv,
+                    },
+        .private_data = &ssc_info[2],
+        },
+};
+EXPORT_SYMBOL_GPL(at32_ssc_dai);
+
+
+MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
+MODULE_DESCRIPTION("AT32 SSC ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h
new file mode 100644 (file)
index 0000000..3c052db
--- /dev/null
@@ -0,0 +1,59 @@
+/* sound/soc/at32/at32-ssc.h
+ * ASoC SSC interface for Atmel AT32 SoC
+ *
+ * Copyright (C) 2008 Long Range Systems
+ *    Geoffrey Wossum <gwossum@acm.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.
+ */
+
+#ifndef __SOUND_SOC_AT32_AT32_SSC_H
+#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__
+
+#include <linux/types.h>
+#include <linux/atmel-ssc.h>
+
+#include "at32-pcm.h"
+
+
+
+struct at32_ssc_state {
+       u32 ssc_cmr;
+       u32 ssc_rcmr;
+       u32 ssc_rfmr;
+       u32 ssc_tcmr;
+       u32 ssc_tfmr;
+       u32 ssc_sr;
+       u32 ssc_imr;
+};
+
+
+
+struct at32_ssc_info {
+       char *name;
+       struct ssc_device *ssc;
+       spinlock_t lock;        /* lock for dir_mask */
+       unsigned short dir_mask;        /* 0=unused, 1=playback, 2=capture */
+       unsigned short initialized;     /* true if SSC has been initialized */
+       unsigned short daifmt;
+       unsigned short cmr_div;
+       unsigned short tcmr_period;
+       unsigned short rcmr_period;
+       struct at32_pcm_dma_params *dma_params[2];
+       struct at32_ssc_state ssc_state;
+};
+
+
+/* SSC divider ids */
+#define AT32_SSC_CMR_DIV        0      /* MCK divider for BCLK */
+#define AT32_SSC_TCMR_PERIOD    1      /* BCLK divider for transmit FS */
+#define AT32_SSC_RCMR_PERIOD    2      /* BCLK divider for receive FS */
+
+
+extern struct snd_soc_dai at32_ssc_dai[];
+
+
+
+#endif /* __SOUND_SOC_AT32_AT32_SSC_H */
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c
new file mode 100644 (file)
index 0000000..fee5f8e
--- /dev/null
@@ -0,0 +1,522 @@
+/* sound/soc/at32/playpaq_wm8510.c
+ * ASoC machine driver for PlayPaq using WM8510 codec
+ *
+ * Copyright (C) 2008 Long Range Systems
+ *    Geoffrey Wossum <gwossum@acm.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.
+ *
+ * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c
+ *
+ * NOTE: If you don't have the AT32 enhanced portmux configured (which
+ * isn't currently in the mainline or Atmel patched kernel), you will
+ * need to set the MCLK pin (PA30) to peripheral A in your board initialization
+ * code.  Something like:
+ *     at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+ *
+ */
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/arch/at32ap700x.h>
+#include <asm/arch/portmux.h>
+
+#include "../codecs/wm8510.h"
+#include "at32-pcm.h"
+#include "at32-ssc.h"
+
+
+/*-------------------------------------------------------------------------*\
+ * constants
+\*-------------------------------------------------------------------------*/
+#define MCLK_PIN               GPIO_PIN_PA(30)
+#define MCLK_PERIPH            GPIO_PERIPH_A
+
+
+/*-------------------------------------------------------------------------*\
+ * data types
+\*-------------------------------------------------------------------------*/
+/* SSC clocking data */
+struct ssc_clock_data {
+       /* CMR div */
+       unsigned int cmr_div;
+
+       /* Frame period (as needed by xCMR.PERIOD) */
+       unsigned int period;
+
+       /* The SSC clock rate these settings where calculated for */
+       unsigned long ssc_rate;
+};
+
+
+/*-------------------------------------------------------------------------*\
+ * module data
+\*-------------------------------------------------------------------------*/
+static struct clk *_gclk0;
+static struct clk *_pll0;
+
+#define CODEC_CLK (_gclk0)
+
+
+/*-------------------------------------------------------------------------*\
+ * Sound SOC operations
+\*-------------------------------------------------------------------------*/
+#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
+static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
+       struct snd_pcm_hw_params *params,
+       struct snd_soc_dai *cpu_dai)
+{
+       struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+       struct ssc_device *ssc = ssc_p->ssc;
+       struct ssc_clock_data cd;
+       unsigned int rate, width_bits, channels;
+       unsigned int bitrate, ssc_div;
+       unsigned actual_rate;
+
+
+       /*
+        * Figure out required bitrate
+        */
+       rate = params_rate(params);
+       channels = params_channels(params);
+       width_bits = snd_pcm_format_physical_width(params_format(params));
+       bitrate = rate * width_bits * channels;
+
+
+       /*
+        * Figure out required SSC divider and period for required bitrate
+        */
+       cd.ssc_rate = clk_get_rate(ssc->clk);
+       ssc_div = cd.ssc_rate / bitrate;
+       cd.cmr_div = ssc_div / 2;
+       if (ssc_div & 1) {
+               /* round cmr_div up */
+               cd.cmr_div++;
+       }
+       cd.period = width_bits - 1;
+
+
+       /*
+        * Find actual rate, compare to requested rate
+        */
+       actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1));
+       pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n",
+                rate, actual_rate);
+
+
+       return cd;
+}
+#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
+
+
+
+static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+       struct ssc_device *ssc = ssc_p->ssc;
+       unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
+       int ret;
+
+
+       /* Due to difficulties with getting the correct clocks from the AT32's
+        * PLL0, we're going to let the CODEC be in charge of all the clocks
+        */
+#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
+       const unsigned int fmt = (SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+#else
+       struct ssc_clock_data cd;
+       const unsigned int fmt = (SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS);
+#endif
+
+       if (ssc == NULL) {
+               pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n");
+               return -EINVAL;
+       }
+
+
+       /*
+        * Figure out PLL and BCLK dividers for WM8510
+        */
+       switch (params_rate(params)) {
+       case 48000:
+               pll_out = 12288000;
+               mclk_div = WM8510_MCLKDIV_1;
+               bclk = WM8510_BCLKDIV_8;
+               break;
+
+       case 44100:
+               pll_out = 11289600;
+               mclk_div = WM8510_MCLKDIV_1;
+               bclk = WM8510_BCLKDIV_8;
+               break;
+
+       case 22050:
+               pll_out = 11289600;
+               mclk_div = WM8510_MCLKDIV_2;
+               bclk = WM8510_BCLKDIV_8;
+               break;
+
+       case 16000:
+               pll_out = 12288000;
+               mclk_div = WM8510_MCLKDIV_3;
+               bclk = WM8510_BCLKDIV_8;
+               break;
+
+       case 11025:
+               pll_out = 11289600;
+               mclk_div = WM8510_MCLKDIV_4;
+               bclk = WM8510_BCLKDIV_8;
+               break;
+
+       case 8000:
+               pll_out = 12288000;
+               mclk_div = WM8510_MCLKDIV_6;
+               bclk = WM8510_BCLKDIV_8;
+               break;
+
+       default:
+               pr_warning("playpaq_wm8510: Unsupported sample rate %d\n",
+                          params_rate(params));
+               return -EINVAL;
+       }
+
+
+       /*
+        * set CPU and CODEC DAI configuration
+        */
+       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+       if (ret < 0) {
+               pr_warning("playpaq_wm8510: "
+                          "Failed to set CODEC DAI format (%d)\n",
+                          ret);
+               return ret;
+       }
+       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+       if (ret < 0) {
+               pr_warning("playpaq_wm8510: "
+                          "Failed to set CPU DAI format (%d)\n",
+                          ret);
+               return ret;
+       }
+
+
+       /*
+        * Set CPU clock configuration
+        */
+#if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
+       cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai);
+       pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n",
+                cd.cmr_div, cd.period);
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div);
+       if (ret < 0) {
+               pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n",
+                          ret);
+               return ret;
+       }
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD,
+                                         cd.period);
+       if (ret < 0) {
+               pr_warning("playpaq_wm8510: "
+                          "Failed to set CPU transmit period (%d)\n",
+                          ret);
+               return ret;
+       }
+#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
+
+
+       /*
+        * Set CODEC clock configuration
+        */
+       pr_debug("playpaq_wm8510: "
+                "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n",
+                clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div);
+
+
+#if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk);
+       if (ret < 0) {
+               pr_warning
+                   ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n",
+                    ret);
+               return ret;
+       }
+#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
+
+
+       ret = snd_soc_dai_set_pll(codec_dai, 0,
+                                        clk_get_rate(CODEC_CLK), pll_out);
+       if (ret < 0) {
+               pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n",
+                          ret);
+               return ret;
+       }
+
+
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div);
+       if (ret < 0) {
+               pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n",
+                          ret);
+               return ret;
+       }
+
+
+       return 0;
+}
+
+
+
+static struct snd_soc_ops playpaq_wm8510_ops = {
+       .hw_params = playpaq_wm8510_hw_params,
+};
+
+
+
+static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+
+
+static const char *intercon[][3] = {
+       /* speaker connected to SPKOUT */
+       {"Ext Spk", NULL, "SPKOUTP"},
+       {"Ext Spk", NULL, "SPKOUTN"},
+
+       {"Mic Bias", NULL, "Int Mic"},
+       {"MICN", NULL, "Mic Bias"},
+       {"MICP", NULL, "Mic Bias"},
+
+       /* Terminator */
+       {NULL, NULL, NULL},
+};
+
+
+
+static int playpaq_wm8510_init(struct snd_soc_codec *codec)
+{
+       int i;
+
+       /*
+        * Add DAPM widgets
+        */
+       for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++)
+               snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]);
+
+
+
+       /*
+        * Setup audio path interconnects
+        */
+       for (i = 0; intercon[i][0] != NULL; i++) {
+               snd_soc_dapm_connect_input(codec,
+                                          intercon[i][0],
+                                          intercon[i][1], intercon[i][2]);
+       }
+
+
+       /* always connected pins */
+       snd_soc_dapm_enable_pin(codec, "Int Mic");
+       snd_soc_dapm_enable_pin(codec, "Ext Spk");
+       snd_soc_dapm_sync(codec);
+
+
+
+       /* Make CSB show PLL rate */
+       snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
+                                      WM8510_OPCLKDIV_1 | 4);
+
+       return 0;
+}
+
+
+
+static struct snd_soc_dai_link playpaq_wm8510_dai = {
+       .name = "WM8510",
+       .stream_name = "WM8510 PCM",
+       .cpu_dai = &at32_ssc_dai[0],
+       .codec_dai = &wm8510_dai,
+       .init = playpaq_wm8510_init,
+       .ops = &playpaq_wm8510_ops,
+};
+
+
+
+static struct snd_soc_machine snd_soc_machine_playpaq = {
+       .name = "LRS_PlayPaq_WM8510",
+       .dai_link = &playpaq_wm8510_dai,
+       .num_links = 1,
+};
+
+
+
+static struct wm8510_setup_data playpaq_wm8510_setup = {
+       .i2c_address = 0x1a,
+};
+
+
+
+static struct snd_soc_device playpaq_wm8510_snd_devdata = {
+       .machine = &snd_soc_machine_playpaq,
+       .platform = &at32_soc_platform,
+       .codec_dev = &soc_codec_dev_wm8510,
+       .codec_data = &playpaq_wm8510_setup,
+};
+
+static struct platform_device *playpaq_snd_device;
+
+
+static int __init playpaq_asoc_init(void)
+{
+       int ret = 0;
+       struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
+       struct ssc_device *ssc = NULL;
+
+
+       /*
+        * Request SSC device
+        */
+       ssc = ssc_request(0);
+       if (IS_ERR(ssc)) {
+               ret = PTR_ERR(ssc);
+               ssc = NULL;
+               goto err_ssc;
+       }
+       ssc_p->ssc = ssc;
+
+
+       /*
+        * Configure MCLK for WM8510
+        */
+       _gclk0 = clk_get(NULL, "gclk0");
+       if (IS_ERR(_gclk0)) {
+               _gclk0 = NULL;
+               goto err_gclk0;
+       }
+       _pll0 = clk_get(NULL, "pll0");
+       if (IS_ERR(_pll0)) {
+               _pll0 = NULL;
+               goto err_pll0;
+       }
+       if (clk_set_parent(_gclk0, _pll0)) {
+               pr_warning("snd-soc-playpaq: "
+                          "Failed to set PLL0 as parent for DAC clock\n");
+               goto err_set_clk;
+       }
+       clk_set_rate(CODEC_CLK, 12000000);
+       clk_enable(CODEC_CLK);
+
+#if defined CONFIG_AT32_ENHANCED_PORTMUX
+       at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0);
+#endif
+
+
+       /*
+        * Create and register platform device
+        */
+       playpaq_snd_device = platform_device_alloc("soc-audio", 0);
+       if (playpaq_snd_device == NULL) {
+               ret = -ENOMEM;
+               goto err_device_alloc;
+       }
+
+       platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
+       playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
+
+       ret = platform_device_add(playpaq_snd_device);
+       if (ret) {
+               pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n",
+                          ret);
+               goto err_device_add;
+       }
+
+       return 0;
+
+
+err_device_add:
+       if (playpaq_snd_device != NULL) {
+               platform_device_put(playpaq_snd_device);
+               playpaq_snd_device = NULL;
+       }
+err_device_alloc:
+err_set_clk:
+       if (_pll0 != NULL) {
+               clk_put(_pll0);
+               _pll0 = NULL;
+       }
+err_pll0:
+       if (_gclk0 != NULL) {
+               clk_put(_gclk0);
+               _gclk0 = NULL;
+       }
+err_gclk0:
+       if (ssc != NULL) {
+               ssc_free(ssc);
+               ssc = NULL;
+       }
+err_ssc:
+       return ret;
+}
+
+
+static void __exit playpaq_asoc_exit(void)
+{
+       struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
+       struct ssc_device *ssc;
+
+       if (ssc_p != NULL) {
+               ssc = ssc_p->ssc;
+               if (ssc != NULL)
+                       ssc_free(ssc);
+               ssc_p->ssc = NULL;
+       }
+
+       if (_gclk0 != NULL) {
+               clk_put(_gclk0);
+               _gclk0 = NULL;
+       }
+       if (_pll0 != NULL) {
+               clk_put(_pll0);
+               _pll0 = NULL;
+       }
+
+#if defined CONFIG_AT32_ENHANCED_PORTMUX
+       at32_free_pin(MCLK_PIN);
+#endif
+
+       platform_device_unregister(playpaq_snd_device);
+       playpaq_snd_device = NULL;
+}
+
+module_init(playpaq_asoc_init);
+module_exit(playpaq_asoc_exit);
+
+MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
+MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq");
+MODULE_LICENSE("GPL");
index 5cb93fd3a4071d477cd38bab269b2bbfe2fda50d..905186502e0009039efc81919022b9d4ffe44a54 100644 (file)
@@ -1,6 +1,6 @@
 config SND_AT91_SOC
        tristate "SoC Audio for the Atmel AT91 System-on-Chip"
-       depends on ARCH_AT91 && SND_SOC
+       depends on ARCH_AT91
        help
          Say Y or M if you want to add support for codecs attached to
          the AT91 SSC interface. You will also need
index ccac6bd2889c0f56589f2234aa899aeb42b42ff0..d47492b2b6e5db1494e466de57da06248cbc2ac0 100644 (file)
@@ -318,7 +318,7 @@ static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
 static u64 at91_pcm_dmamask = 0xffffffff;
 
 static int at91_pcm_new(struct snd_card *card,
-       struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
+       struct snd_soc_dai *dai, struct snd_pcm *pcm)
 {
        int ret = 0;
 
@@ -367,7 +367,7 @@ static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 #ifdef CONFIG_PM
 static int at91_pcm_suspend(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *dai)
+       struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = dai->runtime;
        struct at91_runtime_data *prtd;
@@ -392,7 +392,7 @@ static int at91_pcm_suspend(struct platform_device *pdev,
 }
 
 static int at91_pcm_resume(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *dai)
+       struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = dai->runtime;
        struct at91_runtime_data *prtd;
index bc35d00a38f86b89778bd86953a165d4075dfef2..c3625b665c5a027ee0ed06f7f8f6582da3a026a2 100644 (file)
@@ -281,7 +281,7 @@ static void at91_ssc_shutdown(struct snd_pcm_substream *substream)
 /*
  * Record the SSC system clock rate.
  */
-static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int dir)
 {
        /*
@@ -303,7 +303,7 @@ static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
 /*
  * Record the DAI format for use in hw_params().
  */
-static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
        struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
@@ -315,7 +315,7 @@ static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
 /*
  * Record SSC clock dividers for use in hw_params().
  */
-static int at91_ssc_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
        int div_id, int div)
 {
        struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
@@ -634,7 +634,7 @@ static int at91_ssc_prepare(struct snd_pcm_substream *substream)
 
 #ifdef CONFIG_PM
 static int at91_ssc_suspend(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *cpu_dai)
+       struct snd_soc_dai *cpu_dai)
 {
        struct at91_ssc_info *ssc_p;
 
@@ -662,7 +662,7 @@ static int at91_ssc_suspend(struct platform_device *pdev,
 }
 
 static int at91_ssc_resume(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *cpu_dai)
+       struct snd_soc_dai *cpu_dai)
 {
        struct at91_ssc_info *ssc_p;
 
@@ -700,7 +700,7 @@ static int at91_ssc_resume(struct platform_device *pdev,
 #define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
                          SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_cpu_dai at91_ssc_dai[NUM_SSC_DEVICES] = {
+struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = {
        {       .name = "at91-ssc0",
                .id = 0,
                .type = SND_SOC_DAI_PCM,
index b188f973df9fea1d0554bf36b26b4ad913649674..6b7bf382d06f78ddbaf2435c35f32a330b66f534 100644 (file)
@@ -21,7 +21,7 @@
 #define AT91SSC_TCMR_PERIOD    1 /* BCLK divider for transmit FS */
 #define AT91SSC_RCMR_PERIOD    2 /* BCLK divider for receive FS */
 
-extern struct snd_soc_cpu_dai at91_ssc_dai[];
+extern struct snd_soc_dai at91_ssc_dai[];
 
 #endif /* _AT91_SSC_H */
 
index 1347dcf3f80b822a300e522d93abbdd2e6ea3202..d532de954241d6bda834fb9df868f411f4bf0df6 100644 (file)
@@ -53,18 +53,18 @@ static struct clk *pllb_clk;
 static int eti_b1_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int ret;
 
        /* cpu clock is the AT91 master clock sent to the SSC */
-       ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
+       ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
                60000000, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
        /* codec system clock is supplied by PCK1, set to 12MHz */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
                12000000, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -87,8 +87,8 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int ret;
 
 #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
@@ -96,13 +96,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream,
        int cmr_div, period;
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
@@ -141,17 +141,17 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set the MCK divider for BCLK */
-       ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
        if (ret < 0)
                return ret;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* set the BCLK divider for DACLRC */
-               ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+               ret = snd_soc_dai_set_clkdiv(cpu_dai,
                                                AT91SSC_TCMR_PERIOD, period);
        } else {
                /* set the BCLK divider for ADCLRC */
-               ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+               ret = snd_soc_dai_set_clkdiv(cpu_dai,
                                                AT91SSC_RCMR_PERIOD, period);
        }
        if (ret < 0)
@@ -163,13 +163,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream,
         */
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
@@ -191,7 +191,7 @@ static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
        SND_SOC_DAPM_SPK("Ext Spk", NULL),
 };
 
-static const char *intercon[][3] = {
+static const struct snd_soc_dapm_route intercon[] = {
 
        /* speaker connected to LHPOUT */
        {"Ext Spk", NULL, "LHPOUT"},
@@ -199,9 +199,6 @@ static const char *intercon[][3] = {
        /* mic is connected to Mic Jack, with WM8731 Mic Bias */
        {"MICIN", NULL, "Mic Bias"},
        {"Mic Bias", NULL, "Int Mic"},
-
-       /* terminator */
-       {NULL, NULL, NULL},
 };
 
 /*
@@ -209,30 +206,24 @@ static const char *intercon[][3] = {
  */
 static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
 {
-       int i;
-
        DBG("eti_b1_wm8731_init() called\n");
 
        /* Add specific widgets */
-       for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) {
-               snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]);
-       }
+       snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
+                                 ARRAY_SIZE(eti_b1_dapm_widgets));
 
        /* Set up specific audio path interconnects */
-       for(i = 0; intercon[i][0] != NULL; i++) {
-               snd_soc_dapm_connect_input(codec, intercon[i][0],
-                       intercon[i][1], intercon[i][2]);
-       }
+       snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
 
        /* not connected */
-       snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
-       snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
+       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_disable_pin(codec, "LLINEIN");
 
        /* always connected */
-       snd_soc_dapm_set_endpoint(codec, "Int Mic", 1);
-       snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+       snd_soc_dapm_enable_pin(codec, "Int Mic");
+       snd_soc_dapm_enable_pin(codec, "Ext Spk");
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 
        return 0;
 }
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
new file mode 100644 (file)
index 0000000..410a893
--- /dev/null
@@ -0,0 +1,32 @@
+##
+## Au1200/Au1550 PSC + DBDMA
+##
+config SND_SOC_AU1XPSC
+       tristate "SoC Audio for Au1200/Au1250/Au1550"
+       depends on SOC_AU1200 || SOC_AU1550
+       help
+         This option enables support for the Programmable Serial
+         Controllers in AC97 and I2S mode, and the Descriptor-Based DMA
+         Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC.
+
+config SND_SOC_AU1XPSC_I2S
+       tristate
+
+config SND_SOC_AU1XPSC_AC97
+       tristate
+       select AC97_BUS
+       select SND_AC97_CODEC
+       select SND_SOC_AC97_BUS
+
+
+##
+## Boards
+##
+config SND_SOC_SAMPLE_PSC_AC97
+       tristate "Sample Au12x0/Au1550 PSC AC97 sound machine"
+       depends on SND_SOC_AU1XPSC
+       select SND_SOC_AU1XPSC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         This is a sample AC97 sound machine for use in Au12x0/Au1550
+         based systems which have audio on PSC1 (e.g. Db1200 demoboard).
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile
new file mode 100644 (file)
index 0000000..6c6950b
--- /dev/null
@@ -0,0 +1,13 @@
+# Au1200/Au1550 PSC audio
+snd-soc-au1xpsc-dbdma-objs := dbdma2.o
+snd-soc-au1xpsc-i2s-objs := psc-i2s.o
+snd-soc-au1xpsc-ac97-objs := psc-ac97.o
+
+obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o
+obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o
+obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o
+
+# Boards
+snd-soc-sample-ac97-objs := sample-ac97.o
+
+obj-$(CONFIG_SND_SOC_SAMPLE_PSC_AC97) += snd-soc-sample-ac97.o
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
new file mode 100644 (file)
index 0000000..1466d93
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * Au12x0/Au1550 PSC ALSA ASoC audio support.
+ *
+ * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
+ *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ * 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.
+ *
+ * DMA glue for Au1x-PSC audio.
+ *
+ * NOTE: all of these drivers can only work with a SINGLE instance
+ *      of a PSC. Multiple independent audio devices are impossible
+ *      with ASoC v1.
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+#include "psc.h"
+
+/*#define PCM_DEBUG*/
+
+#define MSG(x...)      printk(KERN_INFO "au1xpsc_pcm: " x)
+#ifdef PCM_DEBUG
+#define DBG            MSG
+#else
+#define DBG(x...)      do {} while (0)
+#endif
+
+struct au1xpsc_audio_dmadata {
+       /* DDMA control data */
+       unsigned int ddma_id;           /* DDMA direction ID for this PSC */
+       u32 ddma_chan;                  /* DDMA context */
+
+       /* PCM context (for irq handlers) */
+       struct snd_pcm_substream *substream;
+       unsigned long curr_period;      /* current segment DDMA is working on */
+       unsigned long q_period;         /* queue period(s) */
+       unsigned long dma_area;         /* address of queued DMA area */
+       unsigned long dma_area_s;       /* start address of DMA area */
+       unsigned long pos;              /* current byte position being played */
+       unsigned long periods;          /* number of SG segments in total */
+       unsigned long period_bytes;     /* size in bytes of one SG segment */
+
+       /* runtime data */
+       int msbits;
+};
+
+/* instance data. There can be only one, MacLeod!!!! */
+static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
+
+/*
+ * These settings are somewhat okay, at least on my machine audio plays
+ * almost skip-free. Especially the 64kB buffer seems to help a LOT.
+ */
+#define AU1XPSC_PERIOD_MIN_BYTES       1024
+#define AU1XPSC_BUFFER_MIN_BYTES       65536
+
+#define AU1XPSC_PCM_FMTS                                       \
+       (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_U8 |        \
+        SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |    \
+        SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |    \
+        SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |    \
+        SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE |    \
+        0)
+
+/* PCM hardware DMA capabilities - platform specific */
+static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
+       .info             = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+                           SNDRV_PCM_INFO_INTERLEAVED,
+       .formats          = AU1XPSC_PCM_FMTS,
+       .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
+       .period_bytes_max = 4096 * 1024 - 1,
+       .periods_min      = 2,
+       .periods_max      = 4096,       /* 2 to as-much-as-you-like */
+       .buffer_bytes_max = 4096 * 1024 - 1,
+       .fifo_size        = 16,         /* fifo entries of AC97/I2S PSC */
+};
+
+static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd)
+{
+       au1xxx_dbdma_put_source_flags(cd->ddma_chan,
+                               (void *)phys_to_virt(cd->dma_area),
+                               cd->period_bytes, DDMA_FLAGS_IE);
+
+       /* update next-to-queue period */
+       ++cd->q_period;
+       cd->dma_area += cd->period_bytes;
+       if (cd->q_period >= cd->periods) {
+               cd->q_period = 0;
+               cd->dma_area = cd->dma_area_s;
+       }
+}
+
+static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd)
+{
+       au1xxx_dbdma_put_dest_flags(cd->ddma_chan,
+                               (void *)phys_to_virt(cd->dma_area),
+                               cd->period_bytes, DDMA_FLAGS_IE);
+
+       /* update next-to-queue period */
+       ++cd->q_period;
+       cd->dma_area += cd->period_bytes;
+       if (cd->q_period >= cd->periods) {
+               cd->q_period = 0;
+               cd->dma_area = cd->dma_area_s;
+       }
+}
+
+static void au1x_pcm_dmatx_cb(int irq, void *dev_id)
+{
+       struct au1xpsc_audio_dmadata *cd = dev_id;
+
+       cd->pos += cd->period_bytes;
+       if (++cd->curr_period >= cd->periods) {
+               cd->pos = 0;
+               cd->curr_period = 0;
+       }
+       snd_pcm_period_elapsed(cd->substream);
+       au1x_pcm_queue_tx(cd);
+}
+
+static void au1x_pcm_dmarx_cb(int irq, void *dev_id)
+{
+       struct au1xpsc_audio_dmadata *cd = dev_id;
+
+       cd->pos += cd->period_bytes;
+       if (++cd->curr_period >= cd->periods) {
+               cd->pos = 0;
+               cd->curr_period = 0;
+       }
+       snd_pcm_period_elapsed(cd->substream);
+       au1x_pcm_queue_rx(cd);
+}
+
+static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd)
+{
+       if (pcd->ddma_chan) {
+               au1xxx_dbdma_stop(pcd->ddma_chan);
+               au1xxx_dbdma_reset(pcd->ddma_chan);
+               au1xxx_dbdma_chan_free(pcd->ddma_chan);
+               pcd->ddma_chan = 0;
+               pcd->msbits = 0;
+       }
+}
+
+/* in case of missing DMA ring or changed TX-source / RX-dest bit widths,
+ * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according
+ * to ALSA-supplied sample depth.  This is due to limitations in the dbdma api
+ * (cannot adjust source/dest widths of already allocated descriptor ring).
+ */
+static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
+                                int stype, int msbits)
+{
+       /* DMA only in 8/16/32 bit widths */
+       if (msbits == 24)
+               msbits = 32;
+
+       /* check current config: correct bits and descriptors allocated? */
+       if ((pcd->ddma_chan) && (msbits == pcd->msbits))
+               goto out;       /* all ok! */
+
+       au1x_pcm_dbdma_free(pcd);
+
+       if (stype == PCM_RX)
+               pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
+                                       DSCR_CMD0_ALWAYS,
+                                       au1x_pcm_dmarx_cb, (void *)pcd);
+       else
+               pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
+                                       pcd->ddma_id,
+                                       au1x_pcm_dmatx_cb, (void *)pcd);
+
+       if (!pcd->ddma_chan)
+               return -ENOMEM;;
+
+       au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits);
+       au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2);
+
+       pcd->msbits = msbits;
+
+       au1xxx_dbdma_stop(pcd->ddma_chan);
+       au1xxx_dbdma_reset(pcd->ddma_chan);
+
+out:
+       return 0;
+}
+
+static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct au1xpsc_audio_dmadata *pcd;
+       int stype, ret;
+
+       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+       if (ret < 0)
+               goto out;
+
+       stype = SUBSTREAM_TYPE(substream);
+       pcd = au1xpsc_audio_pcmdma[stype];
+
+       DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
+           "runtime->min_align %d\n",
+               (unsigned long)runtime->dma_area,
+               (unsigned long)runtime->dma_addr, runtime->dma_bytes,
+               runtime->min_align);
+
+       DBG("bits %d  frags %d  frag_bytes %d  is_rx %d\n", params->msbits,
+               params_periods(params), params_period_bytes(params), stype);
+
+       ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits);
+       if (ret) {
+               MSG("DDMA channel (re)alloc failed!\n");
+               goto out;
+       }
+
+       pcd->substream = substream;
+       pcd->period_bytes = params_period_bytes(params);
+       pcd->periods = params_periods(params);
+       pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr;
+       pcd->q_period = 0;
+       pcd->curr_period = 0;
+       pcd->pos = 0;
+
+       ret = 0;
+out:
+       return ret;
+}
+
+static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct au1xpsc_audio_dmadata *pcd =
+                       au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+
+       au1xxx_dbdma_reset(pcd->ddma_chan);
+
+       if (SUBSTREAM_TYPE(substream) == PCM_RX) {
+               au1x_pcm_queue_rx(pcd);
+               au1x_pcm_queue_rx(pcd);
+       } else {
+               au1x_pcm_queue_tx(pcd);
+               au1x_pcm_queue_tx(pcd);
+       }
+
+       return 0;
+}
+
+static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               au1xxx_dbdma_start(c);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               au1xxx_dbdma_stop(c);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static snd_pcm_uframes_t
+au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       return bytes_to_frames(substream->runtime,
+               au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+}
+
+static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
+{
+       snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
+       return 0;
+}
+
+static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
+{
+       au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+       return 0;
+}
+
+struct snd_pcm_ops au1xpsc_pcm_ops = {
+       .open           = au1xpsc_pcm_open,
+       .close          = au1xpsc_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = au1xpsc_pcm_hw_params,
+       .hw_free        = au1xpsc_pcm_hw_free,
+       .prepare        = au1xpsc_pcm_prepare,
+       .trigger        = au1xpsc_pcm_trigger,
+       .pointer        = au1xpsc_pcm_pointer,
+};
+
+static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int au1xpsc_pcm_new(struct snd_card *card,
+                          struct snd_soc_dai *dai,
+                          struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+               card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
+
+       return 0;
+}
+
+static int au1xpsc_pcm_probe(struct platform_device *pdev)
+{
+       struct resource *r;
+       int ret;
+
+       if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
+               return -EBUSY;
+
+       /* TX DMA */
+       au1xpsc_audio_pcmdma[PCM_TX]
+               = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+       if (!au1xpsc_audio_pcmdma[PCM_TX])
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!r) {
+               ret = -ENODEV;
+               goto out1;
+       }
+       (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+
+       /* RX DMA */
+       au1xpsc_audio_pcmdma[PCM_RX]
+               = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+       if (!au1xpsc_audio_pcmdma[PCM_RX])
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!r) {
+               ret = -ENODEV;
+               goto out2;
+       }
+       (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+
+       return 0;
+
+out2:
+       kfree(au1xpsc_audio_pcmdma[PCM_RX]);
+       au1xpsc_audio_pcmdma[PCM_RX] = NULL;
+out1:
+       kfree(au1xpsc_audio_pcmdma[PCM_TX]);
+       au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+       return ret;
+}
+
+static int au1xpsc_pcm_remove(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               if (au1xpsc_audio_pcmdma[i]) {
+                       au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
+                       kfree(au1xpsc_audio_pcmdma[i]);
+                       au1xpsc_audio_pcmdma[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
+/* au1xpsc audio platform */
+struct snd_soc_platform au1xpsc_soc_platform = {
+       .name           = "au1xpsc-pcm-dbdma",
+       .probe          = au1xpsc_pcm_probe,
+       .remove         = au1xpsc_pcm_remove,
+       .pcm_ops        = &au1xpsc_pcm_ops,
+       .pcm_new        = au1xpsc_pcm_new,
+       .pcm_free       = au1xpsc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
+
+static int __init au1xpsc_audio_dbdma_init(void)
+{
+       au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+       au1xpsc_audio_pcmdma[PCM_RX] = NULL;
+       return 0;
+}
+
+static void __exit au1xpsc_audio_dbdma_exit(void)
+{
+}
+
+module_init(au1xpsc_audio_dbdma_init);
+module_exit(au1xpsc_audio_dbdma_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
new file mode 100644 (file)
index 0000000..57facba
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Au12x0/Au1550 PSC ALSA ASoC audio support.
+ *
+ * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
+ *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ * 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.
+ *
+ * Au1xxx-PSC AC97 glue.
+ *
+ * NOTE: all of these drivers can only work with a SINGLE instance
+ *      of a PSC. Multiple independent audio devices are impossible
+ *      with ASoC v1.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+#include "psc.h"
+
+#define AC97_DIR       \
+       (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AC97_RATES     \
+       SNDRV_PCM_RATE_8000_48000
+
+#define AC97_FMTS      \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE)
+
+#define AC97PCR_START(stype)   \
+       ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
+#define AC97PCR_STOP(stype)    \
+       ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
+#define AC97PCR_CLRFIFO(stype) \
+       ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
+
+/* instance data. There can be only one, MacLeod!!!! */
+static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
+
+/* AC97 controller reads codec register */
+static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
+                                       unsigned short reg)
+{
+       /* FIXME */
+       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       unsigned short data, tmo;
+
+       au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata));
+       au_sync();
+
+       tmo = 1000;
+       while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo)
+               udelay(2);
+
+       if (!tmo)
+               data = 0xffff;
+       else
+               data = au_readl(AC97_CDC(pscdata)) & 0xffff;
+
+       au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
+       au_sync();
+
+       return data;
+}
+
+/* AC97 controller writes to codec register */
+static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                               unsigned short val)
+{
+       /* FIXME */
+       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       unsigned int tmo;
+
+       au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata));
+       au_sync();
+       tmo = 1000;
+       while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo)
+               au_sync();
+
+       au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
+       au_sync();
+}
+
+/* AC97 controller asserts a warm reset */
+static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       /* FIXME */
+       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+
+       au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
+       au_sync();
+       msleep(10);
+       au_writel(0, AC97_RST(pscdata));
+       au_sync();
+}
+
+static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       /* FIXME */
+       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       int i;
+
+       /* disable PSC during cold reset */
+       au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+       au_sync();
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata));
+       au_sync();
+
+       /* issue cold reset */
+       au_writel(PSC_AC97RST_RST, AC97_RST(pscdata));
+       au_sync();
+       msleep(500);
+       au_writel(0, AC97_RST(pscdata));
+       au_sync();
+
+       /* enable PSC */
+       au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata));
+       au_sync();
+
+       /* wait for PSC to indicate it's ready */
+       i = 100000;
+       while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i))
+               au_sync();
+
+       if (i == 0) {
+               printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n");
+               return;
+       }
+
+       /* enable the ac97 function */
+       au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
+       au_sync();
+
+       /* wait for AC97 core to become ready */
+       i = 100000;
+       while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i))
+               au_sync();
+       if (i == 0)
+               printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n");
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read           = au1xpsc_ac97_read,
+       .write          = au1xpsc_ac97_write,
+       .reset          = au1xpsc_ac97_cold_reset,
+       .warm_reset     = au1xpsc_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params)
+{
+       /* FIXME */
+       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       unsigned long r, stat;
+       int chans, stype = SUBSTREAM_TYPE(substream);
+
+       chans = params_channels(params);
+
+       r = au_readl(AC97_CFG(pscdata));
+       stat = au_readl(AC97_STAT(pscdata));
+
+       /* already active? */
+       if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) {
+               /* reject parameters not currently set up */
+               if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) ||
+                   (pscdata->rate != params_rate(params)))
+                       return -EINVAL;
+       } else {
+               /* disable AC97 device controller first */
+               au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
+               au_sync();
+
+               /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */
+               r &= ~PSC_AC97CFG_LEN_MASK;
+               r |= PSC_AC97CFG_SET_LEN(params->msbits);
+
+               /* channels: enable slots for front L/R channel */
+               if (stype == PCM_TX) {
+                       r &= ~PSC_AC97CFG_TXSLOT_MASK;
+                       r |= PSC_AC97CFG_TXSLOT_ENA(3);
+                       r |= PSC_AC97CFG_TXSLOT_ENA(4);
+               } else {
+                       r &= ~PSC_AC97CFG_RXSLOT_MASK;
+                       r |= PSC_AC97CFG_RXSLOT_ENA(3);
+                       r |= PSC_AC97CFG_RXSLOT_ENA(4);
+               }
+
+               /* finally enable the AC97 controller again */
+               au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
+               au_sync();
+
+               pscdata->cfg = r;
+               pscdata->rate = params_rate(params);
+       }
+
+       return 0;
+}
+
+static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
+                               int cmd)
+{
+       /* FIXME */
+       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       int ret, stype = SUBSTREAM_TYPE(substream);
+
+       ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               au_writel(AC97PCR_START(stype), AC97_PCR(pscdata));
+               au_sync();
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata));
+               au_sync();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int au1xpsc_ac97_probe(struct platform_device *pdev,
+                             struct snd_soc_dai *dai)
+{
+       int ret;
+       struct resource *r;
+       unsigned long sel;
+
+       if (au1xpsc_ac97_workdata)
+               return -EBUSY;
+
+       au1xpsc_ac97_workdata =
+               kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+       if (!au1xpsc_ac97_workdata)
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               ret = -ENODEV;
+               goto out0;
+       }
+
+       ret = -EBUSY;
+       au1xpsc_ac97_workdata->ioarea =
+               request_mem_region(r->start, r->end - r->start + 1,
+                                       "au1xpsc_ac97");
+       if (!au1xpsc_ac97_workdata->ioarea)
+               goto out0;
+
+       au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff);
+       if (!au1xpsc_ac97_workdata->mmio)
+               goto out1;
+
+       /* configuration: max dma trigger threshold, enable ac97 */
+        au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 |
+                                     PSC_AC97CFG_TT_FIFO8 |
+                                     PSC_AC97CFG_DE_ENABLE;
+
+       /* preserve PSC clock source set up by platform (dev.platform_data
+        * is already occupied by soc layer)
+        */
+       sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK;
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+       au_sync();
+       au_writel(0, PSC_SEL(au1xpsc_ac97_workdata));
+       au_sync();
+       au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata));
+       au_sync();
+       /* next up: cold reset.  Dont check for PSC-ready now since
+        * there may not be any codec clock yet.
+        */
+
+       return 0;
+
+out1:
+       release_resource(au1xpsc_ac97_workdata->ioarea);
+       kfree(au1xpsc_ac97_workdata->ioarea);
+out0:
+       kfree(au1xpsc_ac97_workdata);
+       au1xpsc_ac97_workdata = NULL;
+       return ret;
+}
+
+static void au1xpsc_ac97_remove(struct platform_device *pdev,
+                               struct snd_soc_dai *dai)
+{
+       /* disable PSC completely */
+       au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+       au_sync();
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+       au_sync();
+
+       iounmap(au1xpsc_ac97_workdata->mmio);
+       release_resource(au1xpsc_ac97_workdata->ioarea);
+       kfree(au1xpsc_ac97_workdata->ioarea);
+       kfree(au1xpsc_ac97_workdata);
+       au1xpsc_ac97_workdata = NULL;
+}
+
+static int au1xpsc_ac97_suspend(struct platform_device *pdev,
+                               struct snd_soc_dai *dai)
+{
+       /* save interesting registers and disable PSC */
+       au1xpsc_ac97_workdata->pm[0] =
+                       au_readl(PSC_SEL(au1xpsc_ac97_workdata));
+
+       au_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
+       au_sync();
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata));
+       au_sync();
+
+       return 0;
+}
+
+static int au1xpsc_ac97_resume(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
+{
+       /* restore PSC clock config */
+       au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE,
+                       PSC_SEL(au1xpsc_ac97_workdata));
+       au_sync();
+
+       /* after this point the ac97 core will cold-reset the codec.
+        * During cold-reset the PSC is reinitialized and the last
+        * configuration set up in hw_params() is restored.
+        */
+       return 0;
+}
+
+struct snd_soc_dai au1xpsc_ac97_dai = {
+       .name                   = "au1xpsc_ac97",
+       .type                   = SND_SOC_DAI_AC97,
+       .probe                  = au1xpsc_ac97_probe,
+       .remove                 = au1xpsc_ac97_remove,
+       .suspend                = au1xpsc_ac97_suspend,
+       .resume                 = au1xpsc_ac97_resume,
+       .playback = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .capture = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .ops = {
+               .trigger        = au1xpsc_ac97_trigger,
+               .hw_params      = au1xpsc_ac97_hw_params,
+       },
+};
+EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
+
+static int __init au1xpsc_ac97_init(void)
+{
+       au1xpsc_ac97_workdata = NULL;
+       return 0;
+}
+
+static void __exit au1xpsc_ac97_exit(void)
+{
+}
+
+module_init(au1xpsc_ac97_init);
+module_exit(au1xpsc_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
new file mode 100644 (file)
index 0000000..ba4b5c1
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Au12x0/Au1550 PSC ALSA ASoC audio support.
+ *
+ * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
+ *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ * 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.
+ *
+ * Au1xxx-PSC I2S glue.
+ *
+ * NOTE: all of these drivers can only work with a SINGLE instance
+ *      of a PSC. Multiple independent audio devices are impossible
+ *      with ASoC v1.
+ * NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+#include "psc.h"
+
+/* supported I2S DAI hardware formats */
+#define AU1XPSC_I2S_DAIFMT \
+       (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J |   \
+        SND_SOC_DAIFMT_NB_NF)
+
+/* supported I2S direction */
+#define AU1XPSC_I2S_DIR \
+       (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AU1XPSC_I2S_RATES \
+       SNDRV_PCM_RATE_8000_192000
+
+#define AU1XPSC_I2S_FMTS \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+#define I2SSTAT_BUSY(stype)    \
+       ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB)
+#define I2SPCR_START(stype)    \
+       ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS)
+#define I2SPCR_STOP(stype)     \
+       ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP)
+#define I2SPCR_CLRFIFO(stype)  \
+       ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
+
+
+/* instance data. There can be only one, MacLeod!!!! */
+static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
+
+static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+                              unsigned int fmt)
+{
+       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       unsigned long ct;
+       int ret;
+
+       ret = -EINVAL;
+
+       ct = pscdata->cfg;
+
+       ct &= ~(PSC_I2SCFG_XM | PSC_I2SCFG_MLJ);        /* left-justified */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ct |= PSC_I2SCFG_XM;    /* enable I2S mode */
+               break;
+       case SND_SOC_DAIFMT_MSB:
+               break;
+       case SND_SOC_DAIFMT_LSB:
+               ct |= PSC_I2SCFG_MLJ;   /* LSB (right-) justified */
+               break;
+       default:
+               goto out;
+       }
+
+       ct &= ~(PSC_I2SCFG_BI | PSC_I2SCFG_WI);         /* IB-IF */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               ct |= PSC_I2SCFG_BI | PSC_I2SCFG_WI;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               ct |= PSC_I2SCFG_BI;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               ct |= PSC_I2SCFG_WI;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               break;
+       default:
+               goto out;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:    /* CODEC master */
+               ct |= PSC_I2SCFG_MS;    /* PSC I2S slave mode */
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:    /* CODEC slave */
+               ct &= ~PSC_I2SCFG_MS;   /* PSC I2S Master mode */
+               break;
+       default:
+               goto out;
+       }
+
+       pscdata->cfg = ct;
+       ret = 0;
+out:
+       return ret;
+}
+
+static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+
+       int cfgbits;
+       unsigned long stat;
+
+       /* check if the PSC is already streaming data */
+       stat = au_readl(I2S_STAT(pscdata));
+       if (stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB)) {
+               /* reject parameters not currently set up in hardware */
+               cfgbits = au_readl(I2S_CFG(pscdata));
+               if ((PSC_I2SCFG_GET_LEN(cfgbits) != params->msbits) ||
+                   (params_rate(params) != pscdata->rate))
+                       return -EINVAL;
+       } else {
+               /* set sample bitdepth */
+               pscdata->cfg &= ~(0x1f << 4);
+               pscdata->cfg |= PSC_I2SCFG_SET_LEN(params->msbits);
+               /* remember current rate for other stream */
+               pscdata->rate = params_rate(params);
+       }
+       return 0;
+}
+
+/* Configure PSC late:  on my devel systems the codec  is I2S master and
+ * supplies the i2sbitclock __AND__ i2sMclk (!) to the PSC unit.  ASoC
+ * uses aggressive PM and  switches the codec off  when it is not in use
+ * which also means the PSC unit doesn't get any clocks and is therefore
+ * dead. That's why this chunk here gets called from the trigger callback
+ * because I can be reasonably certain the codec is driving the clocks.
+ */
+static int au1xpsc_i2s_configure(struct au1xpsc_audio_data *pscdata)
+{
+       unsigned long tmo;
+
+       /* bring PSC out of sleep, and configure I2S unit */
+       au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata));
+       au_sync();
+
+       tmo = 1000000;
+       while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo)
+               tmo--;
+
+       if (!tmo)
+               goto psc_err;
+
+       au_writel(0, I2S_CFG(pscdata));
+       au_sync();
+       au_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata));
+       au_sync();
+
+       /* wait for I2S controller to become ready */
+       tmo = 1000000;
+       while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo)
+               tmo--;
+
+       if (tmo)
+               return 0;
+
+psc_err:
+       au_writel(0, I2S_CFG(pscdata));
+       au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata));
+       au_sync();
+       return -ETIMEDOUT;
+}
+
+static int au1xpsc_i2s_start(struct au1xpsc_audio_data *pscdata, int stype)
+{
+       unsigned long tmo, stat;
+       int ret;
+
+       ret = 0;
+
+       /* if both TX and RX are idle, configure the PSC  */
+       stat = au_readl(I2S_STAT(pscdata));
+       if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) {
+               ret = au1xpsc_i2s_configure(pscdata);
+               if (ret)
+                       goto out;
+       }
+
+       au_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata));
+       au_sync();
+       au_writel(I2SPCR_START(stype), I2S_PCR(pscdata));
+       au_sync();
+
+       /* wait for start confirmation */
+       tmo = 1000000;
+       while (!(au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo)
+               tmo--;
+
+       if (!tmo) {
+               au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata));
+               au_sync();
+               ret = -ETIMEDOUT;
+       }
+out:
+       return ret;
+}
+
+static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
+{
+       unsigned long tmo, stat;
+
+       au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata));
+       au_sync();
+
+       /* wait for stop confirmation */
+       tmo = 1000000;
+       while ((au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo)
+               tmo--;
+
+       /* if both TX and RX are idle, disable PSC */
+       stat = au_readl(I2S_STAT(pscdata));
+       if (!(stat & (PSC_I2SSTAT_RB | PSC_I2SSTAT_RB))) {
+               au_writel(0, I2S_CFG(pscdata));
+               au_sync();
+               au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata));
+               au_sync();
+       }
+       return 0;
+}
+
+static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       int ret, stype = SUBSTREAM_TYPE(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               ret = au1xpsc_i2s_start(pscdata, stype);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               ret = au1xpsc_i2s_stop(pscdata, stype);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int au1xpsc_i2s_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
+{
+       struct resource *r;
+       unsigned long sel;
+       int ret;
+
+       if (au1xpsc_i2s_workdata)
+               return -EBUSY;
+
+       au1xpsc_i2s_workdata =
+               kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+       if (!au1xpsc_i2s_workdata)
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               ret = -ENODEV;
+               goto out0;
+       }
+
+       ret = -EBUSY;
+       au1xpsc_i2s_workdata->ioarea =
+               request_mem_region(r->start, r->end - r->start + 1,
+                                       "au1xpsc_i2s");
+       if (!au1xpsc_i2s_workdata->ioarea)
+               goto out0;
+
+       au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff);
+       if (!au1xpsc_i2s_workdata->mmio)
+               goto out1;
+
+       /* preserve PSC clock source set up by platform (dev.platform_data
+        * is already occupied by soc layer)
+        */
+       sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK;
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_sync();
+       au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata));
+       au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+       au_sync();
+
+       /* preconfigure: set max rx/tx fifo depths */
+       au1xpsc_i2s_workdata->cfg |=
+                       PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8;
+
+       /* don't wait for I2S core to become ready now; clocks may not
+        * be running yet; depending on clock input for PSC a wait might
+        * time out.
+        */
+
+       return 0;
+
+out1:
+       release_resource(au1xpsc_i2s_workdata->ioarea);
+       kfree(au1xpsc_i2s_workdata->ioarea);
+out0:
+       kfree(au1xpsc_i2s_workdata);
+       au1xpsc_i2s_workdata = NULL;
+       return ret;
+}
+
+static void au1xpsc_i2s_remove(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
+{
+       au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+       au_sync();
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_sync();
+
+       iounmap(au1xpsc_i2s_workdata->mmio);
+       release_resource(au1xpsc_i2s_workdata->ioarea);
+       kfree(au1xpsc_i2s_workdata->ioarea);
+       kfree(au1xpsc_i2s_workdata);
+       au1xpsc_i2s_workdata = NULL;
+}
+
+static int au1xpsc_i2s_suspend(struct platform_device *pdev,
+                              struct snd_soc_dai *cpu_dai)
+{
+       /* save interesting register and disable PSC */
+       au1xpsc_i2s_workdata->pm[0] =
+               au_readl(PSC_SEL(au1xpsc_i2s_workdata));
+
+       au_writel(0, I2S_CFG(au1xpsc_i2s_workdata));
+       au_sync();
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_sync();
+
+       return 0;
+}
+
+static int au1xpsc_i2s_resume(struct platform_device *pdev,
+                             struct snd_soc_dai *cpu_dai)
+{
+       /* select I2S mode and PSC clock */
+       au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata));
+       au_sync();
+       au_writel(0, PSC_SEL(au1xpsc_i2s_workdata));
+       au_sync();
+       au_writel(au1xpsc_i2s_workdata->pm[0],
+                       PSC_SEL(au1xpsc_i2s_workdata));
+       au_sync();
+
+       return 0;
+}
+
+struct snd_soc_dai au1xpsc_i2s_dai = {
+       .name                   = "au1xpsc_i2s",
+       .type                   = SND_SOC_DAI_I2S,
+       .probe                  = au1xpsc_i2s_probe,
+       .remove                 = au1xpsc_i2s_remove,
+       .suspend                = au1xpsc_i2s_suspend,
+       .resume                 = au1xpsc_i2s_resume,
+       .playback = {
+               .rates          = AU1XPSC_I2S_RATES,
+               .formats        = AU1XPSC_I2S_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,    /* 2 without external help */
+       },
+       .capture = {
+               .rates          = AU1XPSC_I2S_RATES,
+               .formats        = AU1XPSC_I2S_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,    /* 2 without external help */
+       },
+       .ops = {
+               .trigger        = au1xpsc_i2s_trigger,
+               .hw_params      = au1xpsc_i2s_hw_params,
+       },
+       .dai_ops = {
+               .set_fmt        = au1xpsc_i2s_set_fmt,
+       },
+};
+EXPORT_SYMBOL(au1xpsc_i2s_dai);
+
+static int __init au1xpsc_i2s_init(void)
+{
+       au1xpsc_i2s_workdata = NULL;
+       return 0;
+}
+
+static void __exit au1xpsc_i2s_exit(void)
+{
+}
+
+module_init(au1xpsc_i2s_init);
+module_exit(au1xpsc_i2s_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
new file mode 100644 (file)
index 0000000..8fdb1a0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Au12x0/Au1550 PSC ALSA ASoC audio support.
+ *
+ * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
+ *     Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ * 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.
+ *
+ * NOTE: all of these drivers can only work with a SINGLE instance
+ *      of a PSC. Multiple independent audio devices are impossible
+ *      with ASoC v1.
+ */
+
+#ifndef _AU1X_PCM_H
+#define _AU1X_PCM_H
+
+extern struct snd_soc_dai au1xpsc_ac97_dai;
+extern struct snd_soc_dai au1xpsc_i2s_dai;
+extern struct snd_soc_platform au1xpsc_soc_platform;
+extern struct snd_ac97_bus_ops soc_ac97_ops;
+
+struct au1xpsc_audio_data {
+       void __iomem *mmio;
+
+       unsigned long cfg;
+       unsigned long rate;
+
+       unsigned long pm[2];
+       struct resource *ioarea;
+};
+
+#define PCM_TX 0
+#define PCM_RX 1
+
+#define SUBSTREAM_TYPE(substream) \
+       ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
+
+/* easy access macros */
+#define PSC_CTRL(x)    ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET)
+#define PSC_SEL(x)     ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET)
+#define I2S_STAT(x)    ((unsigned long)((x)->mmio) + PSC_I2SSTAT_OFFSET)
+#define I2S_CFG(x)     ((unsigned long)((x)->mmio) + PSC_I2SCFG_OFFSET)
+#define I2S_PCR(x)     ((unsigned long)((x)->mmio) + PSC_I2SPCR_OFFSET)
+#define AC97_CFG(x)    ((unsigned long)((x)->mmio) + PSC_AC97CFG_OFFSET)
+#define AC97_CDC(x)    ((unsigned long)((x)->mmio) + PSC_AC97CDC_OFFSET)
+#define AC97_EVNT(x)   ((unsigned long)((x)->mmio) + PSC_AC97EVNT_OFFSET)
+#define AC97_PCR(x)    ((unsigned long)((x)->mmio) + PSC_AC97PCR_OFFSET)
+#define AC97_RST(x)    ((unsigned long)((x)->mmio) + PSC_AC97RST_OFFSET)
+#define AC97_STAT(x)   ((unsigned long)((x)->mmio) + PSC_AC97STAT_OFFSET)
+
+#endif
diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c
new file mode 100644 (file)
index 0000000..f75ae7f
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Sample Au12x0/Au1550 PSC AC97 sound machine.
+ *
+ * Copyright (c) 2007-2008 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms outlined in the file COPYING at the root of this
+ *  source archive.
+ *
+ * This is a very generic AC97 sound machine driver for boards which
+ * have (AC97) audio at PSC1 (e.g. DB1200 demoboards).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#include "../codecs/ac97.h"
+#include "psc.h"
+
+static int au1xpsc_sample_ac97_init(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_sync(codec);
+       return 0;
+}
+
+static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = {
+       .name           = "AC97",
+       .stream_name    = "AC97 HiFi",
+       .cpu_dai        = &au1xpsc_ac97_dai,    /* see psc-ac97.c */
+       .codec_dai      = &ac97_dai,            /* see codecs/ac97.c */
+       .init           = au1xpsc_sample_ac97_init,
+       .ops            = NULL,
+};
+
+static struct snd_soc_machine au1xpsc_sample_ac97_machine = {
+       .name           = "Au1xxx PSC AC97 Audio",
+       .dai_link       = &au1xpsc_sample_ac97_dai,
+       .num_links      = 1,
+};
+
+static struct snd_soc_device au1xpsc_sample_ac97_devdata = {
+       .machine        = &au1xpsc_sample_ac97_machine,
+       .platform       = &au1xpsc_soc_platform, /* see dbdma2.c */
+       .codec_dev      = &soc_codec_dev_ac97,
+};
+
+static struct resource au1xpsc_psc1_res[] = {
+       [0] = {
+               .start  = CPHYSADDR(PSC1_BASE_ADDR),
+               .end    = CPHYSADDR(PSC1_BASE_ADDR) + 0x000fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+#ifdef CONFIG_SOC_AU1200
+               .start  = AU1200_PSC1_INT,
+               .end    = AU1200_PSC1_INT,
+#elif defined(CONFIG_SOC_AU1550)
+               .start  = AU1550_PSC1_INT,
+               .end    = AU1550_PSC1_INT,
+#endif
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = DSCR_CMD0_PSC1_TX,
+               .end    = DSCR_CMD0_PSC1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = DSCR_CMD0_PSC1_RX,
+               .end    = DSCR_CMD0_PSC1_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct platform_device *au1xpsc_sample_ac97_dev;
+
+static int __init au1xpsc_sample_ac97_load(void)
+{
+       int ret;
+
+#ifdef CONFIG_SOC_AU1200
+       unsigned long io;
+
+       /* modify sys_pinfunc for AC97 on PSC1 */
+       io = au_readl(SYS_PINFUNC);
+       io |= SYS_PINFUNC_P1C;
+       io &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B);
+       au_writel(io, SYS_PINFUNC);
+       au_sync();
+#endif
+
+       ret = -ENOMEM;
+
+       /* setup PSC clock source for AC97 part: external clock provided
+        * by codec.  The psc-ac97.c driver depends on this setting!
+        */
+       au_writel(PSC_SEL_CLK_SERCLK, PSC1_BASE_ADDR + PSC_SEL_OFFSET);
+       au_sync();
+
+       au1xpsc_sample_ac97_dev = platform_device_alloc("soc-audio", -1);
+       if (!au1xpsc_sample_ac97_dev)
+               goto out;
+
+       au1xpsc_sample_ac97_dev->resource =
+               kmemdup(au1xpsc_psc1_res, sizeof(struct resource) *
+                       ARRAY_SIZE(au1xpsc_psc1_res), GFP_KERNEL);
+       au1xpsc_sample_ac97_dev->num_resources = ARRAY_SIZE(au1xpsc_psc1_res);
+       au1xpsc_sample_ac97_dev->id = 1;
+
+       platform_set_drvdata(au1xpsc_sample_ac97_dev,
+                            &au1xpsc_sample_ac97_devdata);
+       au1xpsc_sample_ac97_devdata.dev = &au1xpsc_sample_ac97_dev->dev;
+       ret = platform_device_add(au1xpsc_sample_ac97_dev);
+
+       if (ret) {
+               platform_device_put(au1xpsc_sample_ac97_dev);
+               au1xpsc_sample_ac97_dev = NULL;
+       }
+
+out:
+       return ret;
+}
+
+static void __exit au1xpsc_sample_ac97_exit(void)
+{
+       platform_device_unregister(au1xpsc_sample_ac97_dev);
+}
+
+module_init(au1xpsc_sample_ac97_load);
+module_exit(au1xpsc_sample_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Au1xxx PSC sample AC97 machine");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index 3903ab7dfa4a78ea2e3eebcbf8526f832b5ebdc4..1db04a28a53d46c7732401a2375ea904db158af6 100644 (file)
@@ -1,31 +1,37 @@
 config SND_SOC_AC97_CODEC
        tristate
-       depends on SND_SOC
+       select SND_AC97_CODEC
+
+config SND_SOC_AK4535
+       tristate
+
+config SND_SOC_UDA1380
+        tristate
+
+config SND_SOC_WM8510
+       tristate
 
 config SND_SOC_WM8731
        tristate
-       depends on SND_SOC
 
 config SND_SOC_WM8750
        tristate
-       depends on SND_SOC
 
 config SND_SOC_WM8753
        tristate
-       depends on SND_SOC
+
+config SND_SOC_WM8990
+       tristate
 
 config SND_SOC_WM9712
        tristate
-       depends on SND_SOC
 
 config SND_SOC_WM9713
        tristate
-       depends on SND_SOC
 
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
        tristate
-       depends on SND_SOC
 
 # Cirrus Logic CS4270 Codec Hardware Mute Support
 # Select if you have external muting circuitry attached to your CS4270.
@@ -43,4 +49,4 @@ config SND_SOC_CS4270_VD33_ERRATA
 
 config SND_SOC_TLV320AIC3X
        tristate
-       depends on SND_SOC && I2C
+       depends on I2C
index 4e1314c9d3ecc44bd8228d383a3d9688bcf9dc45..d7b97abcf7291cea11e2ea29a3c687551f241b4f 100644 (file)
@@ -1,16 +1,24 @@
 snd-soc-ac97-objs := ac97.o
+snd-soc-ak4535-objs := ak4535.o
+snd-soc-uda1380-objs := uda1380.o
+snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8731-objs := wm8731.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
+snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
+obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8731)   += snd-soc-wm8731.o
 obj-$(CONFIG_SND_SOC_WM8750)   += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
+obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
index 2a1ffe39690887efcd9e5ea66628fca8e8d4d531..61fd96ca7bc782588e17655ebd8dd12887837e75 100644 (file)
@@ -10,9 +10,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    17th Oct 2005   Initial version.
- *
  * Generic AC97 support.
  */
 
@@ -24,6 +21,7 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include "ac97.h"
 
 #define AC97_VERSION "0.6"
 
@@ -43,7 +41,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream)
                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000)
 
-struct snd_soc_codec_dai ac97_dai = {
+struct snd_soc_dai ac97_dai = {
        .name = "AC97 HiFi",
        .type = SND_SOC_DAI_AC97,
        .playback = {
@@ -146,9 +144,34 @@ static int ac97_soc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_ac97_suspend(socdev->codec->ac97);
+
+       return 0;
+}
+
+static int ac97_soc_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       snd_ac97_resume(socdev->codec->ac97);
+
+       return 0;
+}
+#else
+#define ac97_soc_suspend NULL
+#define ac97_soc_resume NULL
+#endif
+
 struct snd_soc_codec_device soc_codec_dev_ac97 = {
        .probe =        ac97_soc_probe,
        .remove =       ac97_soc_remove,
+       .suspend =      ac97_soc_suspend,
+       .resume =       ac97_soc_resume,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
 
index 2bf6d69fd0692c204f3a3126edf3eb34ef39249a..281aa42e2bbb95c055ed0a48270a3a83a46d991e 100644 (file)
@@ -14,6 +14,6 @@
 #define __LINUX_SND_SOC_AC97_H
 
 extern struct snd_soc_codec_device soc_codec_dev_ac97;
-extern struct snd_soc_codec_dai ac97_dai;
+extern struct snd_soc_dai ac97_dai;
 
 #endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
new file mode 100644 (file)
index 0000000..b26003c
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * ak4535.c  --  AK4535 ALSA Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "ak4535.h"
+
+#define AUDIO_NAME "ak4535"
+#define AK4535_VERSION "0.3"
+
+struct snd_soc_codec_device soc_codec_dev_ak4535;
+
+/* codec private data */
+struct ak4535_priv {
+       unsigned int sysclk;
+};
+
+/*
+ * ak4535 register cache
+ */
+static const u16 ak4535_reg[AK4535_CACHEREGNUM] = {
+    0x0000, 0x0080, 0x0000, 0x0003,
+    0x0002, 0x0000, 0x0011, 0x0001,
+    0x0000, 0x0040, 0x0036, 0x0010,
+    0x0000, 0x0000, 0x0057, 0x0000,
+};
+
+/*
+ * read ak4535 register cache
+ */
+static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= AK4535_CACHEREGNUM)
+               return -1;
+       return cache[reg];
+}
+
+static inline unsigned int ak4535_read(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u8 data;
+       data = reg;
+
+       if (codec->hw_write(codec->control_data, &data, 1) != 1)
+               return -EIO;
+
+       if (codec->hw_read(codec->control_data, &data, 1) != 1)
+               return -EIO;
+
+       return data;
+};
+
+/*
+ * write ak4535 register cache
+ */
+static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec,
+       u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= AK4535_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the AK4535 register space
+ */
+static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D8 AK4535 register offset
+        *   D7...D0 register data
+        */
+       data[0] = reg & 0xff;
+       data[1] = value & 0xff;
+
+       ak4535_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+static int ak4535_sync(struct snd_soc_codec *codec)
+{
+       u16 *cache = codec->reg_cache;
+       int i, r = 0;
+
+       for (i = 0; i < AK4535_CACHEREGNUM; i++)
+               r |= ak4535_write(codec, i, cache[i]);
+
+       return r;
+};
+
+static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
+static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"};
+static const char *ak4535_hp_out[] = {"Stereo", "Mono"};
+static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"};
+static const char *ak4535_mic_select[] = {"Internal", "External"};
+
+static const struct soc_enum ak4535_enum[] = {
+       SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain),
+       SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out),
+       SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out),
+       SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp),
+       SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select),
+};
+
+static const struct snd_kcontrol_new ak4535_snd_controls[] = {
+       SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0),
+       SOC_ENUM("Mono 1 Output", ak4535_enum[1]),
+       SOC_ENUM("Mono 1 Gain", ak4535_enum[0]),
+       SOC_ENUM("Headphone Output", ak4535_enum[2]),
+       SOC_ENUM("Playback Deemphasis", ak4535_enum[3]),
+       SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0),
+       SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0),
+       SOC_ENUM("Mic Select", ak4535_enum[4]),
+       SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0),
+       SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0),
+       SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0),
+       SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0),
+       SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0),
+       SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0),
+       SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0),
+       SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1),
+       SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1),
+       SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0),
+       SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0),
+};
+
+/* add non dapm controls */
+static int ak4535_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                       snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Mono 1 Mixer */
+static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0),
+       SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0),
+};
+
+/* Stereo Mixer */
+static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0),
+       SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0),
+       SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0),
+};
+
+/* Input Mixer */
+static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0),
+       SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0),
+};
+
+/* Input mux */
+static const struct snd_kcontrol_new ak4535_input_mux_control =
+       SOC_DAPM_ENUM("Input Select", ak4535_enum[4]);
+
+/* HP L switch */
+static const struct snd_kcontrol_new ak4535_hpl_control =
+       SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1);
+
+/* HP R switch */
+static const struct snd_kcontrol_new ak4535_hpr_control =
+       SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1);
+
+/* mono 2 switch */
+static const struct snd_kcontrol_new ak4535_mono2_control =
+       SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0);
+
+/* Line out switch */
+static const struct snd_kcontrol_new ak4535_line_control =
+       SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0);
+
+/* ak4535 dapm widgets */
+static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
+       SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
+               &ak4535_stereo_mixer_controls[0],
+               ARRAY_SIZE(ak4535_stereo_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
+               &ak4535_mono1_mixer_controls[0],
+               ARRAY_SIZE(ak4535_mono1_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
+               &ak4535_input_mixer_controls[0],
+               ARRAY_SIZE(ak4535_input_mixer_controls)),
+       SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+               &ak4535_input_mux_control),
+       SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0),
+       SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
+               &ak4535_mono2_control),
+       /* speaker powersave bit */
+       SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+               &ak4535_line_control),
+       SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0,
+               &ak4535_hpl_control),
+       SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0,
+               &ak4535_hpr_control),
+       SND_SOC_DAPM_OUTPUT("LOUT"),
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("ROUT"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPP"),
+       SND_SOC_DAPM_OUTPUT("SPN"),
+       SND_SOC_DAPM_OUTPUT("MOUT1"),
+       SND_SOC_DAPM_OUTPUT("MOUT2"),
+       SND_SOC_DAPM_OUTPUT("MICOUT"),
+       SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0),
+       SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0),
+       SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0),
+       SND_SOC_DAPM_INPUT("MICIN"),
+       SND_SOC_DAPM_INPUT("MICEXT"),
+       SND_SOC_DAPM_INPUT("AUX"),
+       SND_SOC_DAPM_INPUT("MIN"),
+       SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /*stereo mixer */
+       {"Stereo Mixer", "Playback Switch", "DAC"},
+       {"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
+       {"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
+
+       /* mono1 mixer */
+       {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"},
+       {"Mono1 Mixer", "Mono Playback Switch", "DAC"},
+
+       /* Mic */
+       {"Mic", NULL, "AIN"},
+       {"Input Mux", "Internal", "Mic Int Bias"},
+       {"Input Mux", "External", "Mic Ext Bias"},
+       {"Mic Int Bias", NULL, "MICIN"},
+       {"Mic Ext Bias", NULL, "MICEXT"},
+       {"MICOUT", NULL, "Input Mux"},
+
+       /* line out */
+       {"LOUT", NULL, "Line Out Enable"},
+       {"ROUT", NULL, "Line Out Enable"},
+       {"Line Out Enable", "Switch", "Line Out"},
+       {"Line Out", NULL, "Stereo Mixer"},
+
+       /* mono1 out */
+       {"MOUT1", NULL, "Mono Out"},
+       {"Mono Out", NULL, "Mono1 Mixer"},
+
+       /* left HP */
+       {"HPL", NULL, "Left HP Enable"},
+       {"Left HP Enable", "Switch", "HP L Amp"},
+       {"HP L Amp", NULL, "Stereo Mixer"},
+
+       /* right HP */
+       {"HPR", NULL, "Right HP Enable"},
+       {"Right HP Enable", "Switch", "HP R Amp"},
+       {"HP R Amp", NULL, "Stereo Mixer"},
+
+       /* speaker */
+       {"SPP", NULL, "Speaker Enable"},
+       {"SPN", NULL, "Speaker Enable"},
+       {"Speaker Enable", "Switch", "Spk Amp"},
+       {"Spk Amp", NULL, "MIN"},
+
+       /* mono 2 */
+       {"MOUT2", NULL, "Mono 2 Enable"},
+       {"Mono 2 Enable", "Switch", "Stereo Mixer"},
+
+       /* Aux In */
+       {"Aux In", NULL, "AUX"},
+
+       /* ADC */
+       {"ADC", NULL, "Input Mixer"},
+       {"Input Mixer", "Mic Capture Switch", "Mic"},
+       {"Input Mixer", "Aux Capture Switch", "Aux In"},
+};
+
+static int ak4535_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets,
+                                 ARRAY_SIZE(ak4535_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+       int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct ak4535_priv *ak4535 = codec->private_data;
+
+       ak4535->sysclk = freq;
+       return 0;
+}
+
+static int ak4535_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct ak4535_priv *ak4535 = codec->private_data;
+       u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
+       int rate = params_rate(params), fs = 256;
+
+       if (rate)
+               fs = ak4535->sysclk / rate;
+
+       /* set fs */
+       switch (fs) {
+       case 1024:
+               mode2 |= (0x2 << 5);
+               break;
+       case 512:
+               mode2 |= (0x1 << 5);
+               break;
+       case 256:
+               break;
+       }
+
+       /* set rate */
+       ak4535_write(codec, AK4535_MODE2, mode2);
+       return 0;
+}
+
+static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 mode1 = 0;
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               mode1 = 0x0002;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               mode1 = 0x0001;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* use 32 fs for BCLK to save power */
+       mode1 |= 0x4;
+
+       ak4535_write(codec, AK4535_MODE1, mode1);
+       return 0;
+}
+
+static int ak4535_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+       if (!mute)
+               ak4535_write(codec, AK4535_DAC, mute_reg);
+       else
+               ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
+       return 0;
+}
+
+static int ak4535_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       u16 i;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               ak4535_mute(codec->dai, 0);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               ak4535_mute(codec->dai, 1);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               i = ak4535_read_reg_cache(codec, AK4535_PM1);
+               ak4535_write(codec, AK4535_PM1, i | 0x80);
+               i = ak4535_read_reg_cache(codec, AK4535_PM2);
+               ak4535_write(codec, AK4535_PM2, i & (~0x80));
+               break;
+       case SND_SOC_BIAS_OFF:
+               i = ak4535_read_reg_cache(codec, AK4535_PM1);
+               ak4535_write(codec, AK4535_PM1, i & (~0x80));
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_dai ak4535_dai = {
+       .name = "AK4535",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AK4535_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AK4535_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = {
+               .hw_params = ak4535_hw_params,
+       },
+       .dai_ops = {
+               .set_fmt = ak4535_set_dai_fmt,
+               .digital_mute = ak4535_mute,
+               .set_sysclk = ak4535_set_dai_sysclk,
+       },
+};
+EXPORT_SYMBOL_GPL(ak4535_dai);
+
+static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int ak4535_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       ak4535_sync(codec);
+       ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       ak4535_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+/*
+ * initialise the AK4535 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int ak4535_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+
+       codec->name = "AK4535";
+       codec->owner = THIS_MODULE;
+       codec->read = ak4535_read_reg_cache;
+       codec->write = ak4535_write;
+       codec->set_bias_level = ak4535_set_bias_level;
+       codec->dai = &ak4535_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
+       codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
+
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "ak4535: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* power on device */
+       ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       ak4535_add_controls(codec);
+       ak4535_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "ak4535: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+
+       return ret;
+}
+
+static struct snd_soc_device *ak4535_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+#define I2C_DRIVERID_AK4535 0xfefe /* liam -  need a proper id */
+
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver ak4535_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = ak4535_socdev;
+       struct ak4535_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               printk(KERN_ERR "failed to attach codec at addr %x\n", addr);
+               goto err;
+       }
+
+       ret = ak4535_init(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "failed to initialise AK4535\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int ak4535_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int ak4535_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, ak4535_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver ak4535_i2c_driver = {
+       .driver = {
+               .name = "AK4535 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .id =             I2C_DRIVERID_AK4535,
+       .attach_adapter = ak4535_i2c_attach,
+       .detach_client =  ak4535_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "AK4535",
+       .driver = &ak4535_i2c_driver,
+};
+#endif
+
+static int ak4535_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct ak4535_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct ak4535_priv *ak4535;
+       int ret = 0;
+
+       printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+       if (ak4535 == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = ak4535;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       ak4535_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               codec->hw_read = (hw_read_t)i2c_master_recv;
+               ret = i2c_add_driver(&ak4535_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+       /* Add other interfaces here */
+#endif
+       return ret;
+}
+
+/* power down chip */
+static int ak4535_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&ak4535_i2c_driver);
+#endif
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_ak4535 = {
+       .probe =        ak4535_probe,
+       .remove =       ak4535_remove,
+       .suspend =      ak4535_suspend,
+       .resume =       ak4535_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
+
+MODULE_DESCRIPTION("Soc AK4535 driver");
+MODULE_AUTHOR("Richard Purdie");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h
new file mode 100644 (file)
index 0000000..e9fe30e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * ak4535.h  --  AK4535 Soc Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.h
+ *
+ * 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 _AK4535_H
+#define _AK4535_H
+
+/* AK4535 register space */
+
+#define AK4535_PM1             0x0
+#define AK4535_PM2             0x1
+#define AK4535_SIG1            0x2
+#define AK4535_SIG2            0x3
+#define AK4535_MODE1           0x4
+#define AK4535_MODE2           0x5
+#define AK4535_DAC             0x6
+#define AK4535_MIC             0x7
+#define AK4535_TIMER           0x8
+#define AK4535_ALC1            0x9
+#define AK4535_ALC2            0xa
+#define AK4535_PGA             0xb
+#define AK4535_LATT            0xc
+#define AK4535_RATT            0xd
+#define AK4535_VOL             0xe
+#define AK4535_STATUS          0xf
+
+#define AK4535_CACHEREGNUM     0x10
+
+struct ak4535_setup_data {
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai ak4535_dai;
+extern struct snd_soc_codec_device soc_codec_dev_ak4535;
+
+#endif
index e73fcfd9f5cd41638acbc8d3ad5e30f532fe829f..9deb8c74fdfd3f1c07f5b1eaf518d4b8f145b5d6 100644 (file)
@@ -201,7 +201,7 @@ static struct {
  * driver what the input settings can be.  This would need to be implemented
  * for stand-alone mode to work.
  */
-static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                 int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -251,7 +251,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
  * data for playback only, but ASoC currently does not support different
  * formats for playback vs. record.
  */
-static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -471,7 +471,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
  * board does not have the MUTEA or MUTEB pins connected to such circuitry,
  * then this function will do nothing.
  */
-static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute)
+static int cs4270_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        int reg6;
@@ -667,7 +667,7 @@ error:
 
 #endif /* USE_I2C*/
 
-struct snd_soc_codec_dai cs4270_dai = {
+struct snd_soc_dai cs4270_dai = {
        .name = "CS4270",
        .playback = {
                .stream_name = "Playback",
index 0ced49b7804db22f46719e4ee6957e7e96e908d1..adc6cd9667d4275b3a1035d15de5b5a9c04d0fbf 100644 (file)
@@ -16,7 +16,7 @@
  * The ASoC codec DAI structure for the CS4270.  Assign this structure to
  * the .codec_dai field of your machine driver's snd_soc_dai_link structure.
  */
-extern struct snd_soc_codec_dai cs4270_dai;
+extern struct snd_soc_dai cs4270_dai;
 
 /*
  * The ASoC codec device structure for the CS4270.  Assign this structure
index 09b1661b8a3a3930720947d91cf9a582b642cb0f..b1dce5f459db6d40663112ecb2e3f8eb13bb30a9 100644 (file)
@@ -29,7 +29,7 @@
  *  ---------------------------------------
  *
  *  Hence the machine layer should disable unsupported inputs/outputs by
- *  snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc.
+ *  snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc.
  */
 
 #include <linux/module.h>
@@ -49,7 +49,7 @@
 #include "tlv320aic3x.h"
 
 #define AUDIO_NAME "aic3x"
-#define AIC3X_VERSION "0.1"
+#define AIC3X_VERSION "0.2"
 
 /* codec private data */
 struct aic3x_priv {
@@ -138,6 +138,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
+/*
+ * read from the aic3x register space
+ */
+static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
+                     u8 *value)
+{
+       *value = reg & 0xff;
+       if (codec->hw_read(codec->control_data, value, 1) != 1)
+               return -EIO;
+
+       aic3x_write_reg_cache(codec, reg, *value);
+       return 0;
+}
+
 #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
@@ -192,7 +206,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                }
 
                if (found)
-                       snd_soc_dapm_sync_endpoints(widget->codec);
+                       snd_soc_dapm_sync(widget->codec);
        }
 
        ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
@@ -209,6 +223,8 @@ static const char *aic3x_right_hpcom_mux[] =
     { "differential of HPROUT", "constant VCM", "single-ended",
       "differential of HPLCOM", "external feedback" };
 static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" };
+static const char *aic3x_adc_hpf[] =
+    { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" };
 
 #define LDAC_ENUM      0
 #define RDAC_ENUM      1
@@ -218,6 +234,7 @@ static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" };
 #define LINE1R_ENUM    5
 #define LINE2L_ENUM    6
 #define LINE2R_ENUM    7
+#define ADC_HPF_ENUM   8
 
 static const struct soc_enum aic3x_enum[] = {
        SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux),
@@ -228,6 +245,7 @@ static const struct soc_enum aic3x_enum[] = {
        SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
        SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
        SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+       SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
 };
 
 static const struct snd_kcontrol_new aic3x_snd_controls[] = {
@@ -278,6 +296,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        /* Input */
        SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0),
        SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
+
+       SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
 };
 
 /* add non dapm controls */
@@ -441,11 +461,34 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line2_mux_controls),
 
+       /*
+        * Not a real mic bias widget but similar function. This is for dynamic
+        * control of GPIO1 digital mic modulator clock output function when
+        * using digital mic.
+        */
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk",
+                        AIC3X_GPIO1_REG, 4, 0xf,
+                        AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK,
+                        AIC3X_GPIO1_FUNC_DISABLED),
+
+       /*
+        * Also similar function like mic bias. Selects digital mic with
+        * configurable oversampling rate instead of ADC converter.
+        */
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128",
+                        AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64",
+                        AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
+                        AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
+
        /* Mic Bias */
-       SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0),
-       SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0),
-       SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0),
-       SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V",
+                        MICBIAS_CTRL, 6, 3, 1, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V",
+                        MICBIAS_CTRL, 6, 3, 2, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
+                        MICBIAS_CTRL, 6, 3, 3, 0),
 
        /* Left PGA to Left Output bypass */
        SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
@@ -483,7 +526,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("LINE2R"),
 };
 
-static const char *intercon[][3] = {
+static const struct snd_soc_dapm_route intercon[] = {
        /* Left Output */
        {"Left DAC Mux", "DAC_L1", "Left DAC"},
        {"Left DAC Mux", "DAC_L2", "Left DAC"},
@@ -554,6 +597,7 @@ static const char *intercon[][3] = {
        {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
 
        {"Left ADC", NULL, "Left PGA Mixer"},
+       {"Left ADC", NULL, "GPIO1 dmic modclk"},
 
        /* Right Input */
        {"Right Line1R Mux", "single-ended", "LINE1R"},
@@ -567,6 +611,7 @@ static const char *intercon[][3] = {
        {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Right ADC", NULL, "Right PGA Mixer"},
+       {"Right ADC", NULL, "GPIO1 dmic modclk"},
 
        /* Left PGA Bypass */
        {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"},
@@ -628,101 +673,27 @@ static const char *intercon[][3] = {
        {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
        {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
 
-       /* terminator */
-       {NULL, NULL, NULL},
+       /*
+        * Logical path between digital mic enable and GPIO1 modulator clock
+        * output function
+        */
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
 };
 
 static int aic3x_add_widgets(struct snd_soc_codec *codec)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+                                 ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* set up audio path interconnects */
-       for (i = 0; intercon[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, intercon[i][0],
-                                          intercon[i][1], intercon[i][2]);
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
        snd_soc_dapm_new_widgets(codec);
        return 0;
 }
 
-struct aic3x_rate_divs {
-       u32 mclk;
-       u32 rate;
-       u32 fsref_reg;
-       u8 sr_reg:4;
-       u8 pllj_reg;
-       u16 plld_reg;
-};
-
-/* AIC3X codec mclk clock divider coefficients */
-static const struct aic3x_rate_divs aic3x_divs[] = {
-       /* 8k */
-       {12000000, 8000, 48000, 0xa, 16, 3840},
-       {19200000, 8000, 48000, 0xa, 10, 2400},
-       {22579200, 8000, 48000, 0xa, 8, 7075},
-       {33868800, 8000, 48000, 0xa, 5, 8049},
-       /* 11.025k */
-       {12000000, 11025, 44100, 0x6, 15, 528},
-       {19200000, 11025, 44100, 0x6, 9, 4080},
-       {22579200, 11025, 44100, 0x6, 8, 0},
-       {33868800, 11025, 44100, 0x6, 5, 3333},
-       /* 16k */
-       {12000000, 16000, 48000, 0x4, 16, 3840},
-       {19200000, 16000, 48000, 0x4, 10, 2400},
-       {22579200, 16000, 48000, 0x4, 8, 7075},
-       {33868800, 16000, 48000, 0x4, 5, 8049},
-       /* 22.05k */
-       {12000000, 22050, 44100, 0x2, 15, 528},
-       {19200000, 22050, 44100, 0x2, 9, 4080},
-       {22579200, 22050, 44100, 0x2, 8, 0},
-       {33868800, 22050, 44100, 0x2, 5, 3333},
-       /* 32k */
-       {12000000, 32000, 48000, 0x1, 16, 3840},
-       {19200000, 32000, 48000, 0x1, 10, 2400},
-       {22579200, 32000, 48000, 0x1, 8, 7075},
-       {33868800, 32000, 48000, 0x1, 5, 8049},
-       /* 44.1k */
-       {12000000, 44100, 44100, 0x0, 15, 528},
-       {19200000, 44100, 44100, 0x0, 9, 4080},
-       {22579200, 44100, 44100, 0x0, 8, 0},
-       {33868800, 44100, 44100, 0x0, 5, 3333},
-       /* 48k */
-       {12000000, 48000, 48000, 0x0, 16, 3840},
-       {19200000, 48000, 48000, 0x0, 10, 2400},
-       {22579200, 48000, 48000, 0x0, 8, 7075},
-       {33868800, 48000, 48000, 0x0, 5, 8049},
-       /* 64k */
-       {12000000, 64000, 96000, 0x1, 16, 3840},
-       {19200000, 64000, 96000, 0x1, 10, 2400},
-       {22579200, 64000, 96000, 0x1, 8, 7075},
-       {33868800, 64000, 96000, 0x1, 5, 8049},
-       /* 88.2k */
-       {12000000, 88200, 88200, 0x0, 15, 528},
-       {19200000, 88200, 88200, 0x0, 9, 4080},
-       {22579200, 88200, 88200, 0x0, 8, 0},
-       {33868800, 88200, 88200, 0x0, 5, 3333},
-       /* 96k */
-       {12000000, 96000, 96000, 0x0, 16, 3840},
-       {19200000, 96000, 96000, 0x0, 10, 2400},
-       {22579200, 96000, 96000, 0x0, 8, 7075},
-       {33868800, 96000, 96000, 0x0, 5, 8049},
-};
-
-static inline int aic3x_get_divs(int mclk, int rate)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) {
-               if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk)
-                       return i;
-       }
-
-       return 0;
-}
-
 static int aic3x_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params)
 {
@@ -730,49 +701,107 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->codec;
        struct aic3x_priv *aic3x = codec->private_data;
-       int i;
-       u8 data, pll_p, pll_r, pll_j;
-       u16 pll_d;
-
-       i = aic3x_get_divs(aic3x->sysclk, params_rate(params));
+       int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
+       u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
+       u16 pll_d = 1;
 
-       /* Route Left DAC to left channel input and
-        * right DAC to right channel input */
-       data = (LDAC2LCH | RDAC2RCH);
-       switch (aic3x_divs[i].fsref_reg) {
-       case 44100:
-               data |= FSREF_44100;
+       /* select data word length */
+       data =
+           aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
                break;
-       case 48000:
-               data |= FSREF_48000;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               data |= (0x01 << 4);
                break;
-       case 88200:
-               data |= FSREF_44100 | DUAL_RATE_MODE;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               data |= (0x02 << 4);
                break;
-       case 96000:
-               data |= FSREF_48000 | DUAL_RATE_MODE;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               data |= (0x03 << 4);
                break;
        }
+       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+
+       /* Fsref can be 44100 or 48000 */
+       fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
+
+       /* Try to find a value for Q which allows us to bypass the PLL and
+        * generate CODEC_CLK directly. */
+       for (pll_q = 2; pll_q < 18; pll_q++)
+               if (aic3x->sysclk / (128 * pll_q) == fsref) {
+                       bypass_pll = 1;
+                       break;
+               }
+
+       if (bypass_pll) {
+               pll_q &= 0xf;
+               aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+               aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+       } else
+               aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+
+       /* Route Left DAC to left channel input and
+        * right DAC to right channel input */
+       data = (LDAC2LCH | RDAC2RCH);
+       data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
+       if (params_rate(params) >= 64000)
+               data |= DUAL_RATE_MODE;
        aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
 
        /* codec sample rate select */
-       data = aic3x_divs[i].sr_reg;
+       data = (fsref * 20) / params_rate(params);
+       if (params_rate(params) < 64000)
+               data /= 2;
+       data /= 5;
+       data -= 2;
        data |= (data << 4);
        aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
 
-       /* Use PLL for generation Fsref by equation:
-        * Fsref = (MCLK * K * R)/(2048 * P);
-        * Fix P = 2 and R = 1 and calculate K, if
-        * K = J.D, i.e. J - an interger portion of K and D is the fractional
-        * one with 4 digits of precision;
-        * Example:
-        * For MCLK = 22.5792 MHz and Fsref = 48kHz:
-        * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074
+       if (bypass_pll)
+               return 0;
+
+       /* Use PLL
+        * find an apropriate setup for j, d, r and p by iterating over
+        * p and r - j and d are calculated for each fraction.
+        * Up to 128 values are probed, the closest one wins the game.
+        * The sysclk is divided by 1000 to prevent integer overflows.
         */
-       pll_p = 2;
-       pll_r = 1;
-       pll_j = aic3x_divs[i].pllj_reg;
-       pll_d = aic3x_divs[i].plld_reg;
+       codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
+
+       for (r = 1; r <= 16; r++)
+               for (p = 1; p <= 8; p++) {
+                       int clk, tmp = (codec_clk * pll_r * 10) / pll_p;
+                       u8 j = tmp / 10000;
+                       u16 d = tmp % 10000;
+
+                       if (j > 63)
+                               continue;
+
+                       if (d != 0 && aic3x->sysclk < 10000000)
+                               continue;
+
+                       /* This is actually 1000 * ((j + (d/10000)) * r) / p
+                        * The term had to be converted to get rid of the
+                        * division by 10000 */
+                       clk = ((10000 * j * r) + (d * r)) / (10 * p);
+
+                       /* check whether this values get closer than the best
+                        * ones we had before */
+                       if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
+                               pll_j = j; pll_d = d; pll_r = r; pll_p = p;
+                               last_clk = clk;
+                       }
+
+                       /* Early exit for exact matches */
+                       if (clk == codec_clk)
+                               break;
+               }
+
+       if (last_clk == 0) {
+               printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
+               return -EINVAL;
+       }
 
        data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
        aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
@@ -782,28 +811,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        aic3x_write(codec, AIC3X_PLL_PROGD_REG,
                    (pll_d & 0x3F) << PLLD_LSB_SHIFT);
 
-       /* select data word length */
-       data =
-           aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               break;
-       case SNDRV_PCM_FORMAT_S20_3LE:
-               data |= (0x01 << 4);
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               data |= (0x02 << 4);
-               break;
-       case SNDRV_PCM_FORMAT_S32_LE:
-               data |= (0x03 << 4);
-               break;
-       }
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
-
        return 0;
 }
 
-static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute)
+static int aic3x_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
@@ -820,31 +831,25 @@ static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute)
        return 0;
 }
 
-static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct aic3x_priv *aic3x = codec->private_data;
 
-       switch (freq) {
-       case 12000000:
-       case 19200000:
-       case 22579200:
-       case 33868800:
-               aic3x->sysclk = freq;
-               return 0;
-       }
-
-       return -EINVAL;
+       aic3x->sysclk = freq;
+       return 0;
 }
 
-static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                             unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct aic3x_priv *aic3x = codec->private_data;
-       u8 iface_areg = 0;
-       u8 iface_breg = 0;
+       u8 iface_areg, iface_breg;
+
+       iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+       iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
 
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -883,13 +888,14 @@ static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return 0;
 }
 
-static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
+static int aic3x_set_bias_level(struct snd_soc_codec *codec,
+                               enum snd_soc_bias_level level)
 {
        struct aic3x_priv *aic3x = codec->private_data;
        u8 reg;
 
-       switch (event) {
-       case SNDRV_CTL_POWER_D0:
+       switch (level) {
+       case SND_SOC_BIAS_ON:
                /* all power is driven by DAPM system */
                if (aic3x->master) {
                        /* enable pll */
@@ -898,10 +904,9 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
                                    reg | PLL_ENABLE);
                }
                break;
-       case SNDRV_CTL_POWER_D1:
-       case SNDRV_CTL_POWER_D2:
+       case SND_SOC_BIAS_PREPARE:
                break;
-       case SNDRV_CTL_POWER_D3hot:
+       case SND_SOC_BIAS_STANDBY:
                /*
                 * all power is driven by DAPM system,
                 * so output power is safe if bypass was set
@@ -913,7 +918,7 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
                                    reg & ~PLL_ENABLE);
                }
                break;
-       case SNDRV_CTL_POWER_D3cold:
+       case SND_SOC_BIAS_OFF:
                /* force all power off */
                reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL);
                aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON);
@@ -949,16 +954,43 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
                }
                break;
        }
-       codec->dapm_state = event;
+       codec->bias_level = level;
 
        return 0;
 }
 
+void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
+{
+       u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
+       u8 bit = gpio ? 3: 0;
+       u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
+       aic3x_write(codec, reg, val | (!!state << bit));
+}
+EXPORT_SYMBOL_GPL(aic3x_set_gpio);
+
+int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio)
+{
+       u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
+       u8 val, bit = gpio ? 2: 1;
+
+       aic3x_read(codec, reg, &val);
+       return (val >> bit) & 1;
+}
+EXPORT_SYMBOL_GPL(aic3x_get_gpio);
+
+int aic3x_headset_detected(struct snd_soc_codec *codec)
+{
+       u8 val;
+       aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val);
+       return (val >> 2) & 1;
+}
+EXPORT_SYMBOL_GPL(aic3x_headset_detected);
+
 #define AIC3X_RATES    SNDRV_PCM_RATE_8000_96000
 #define AIC3X_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_codec_dai aic3x_dai = {
+struct snd_soc_dai aic3x_dai = {
        .name = "aic3x",
        .playback = {
                .stream_name = "Playback",
@@ -988,7 +1020,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->codec;
 
-       aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+       aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
@@ -1008,7 +1040,7 @@ static int aic3x_resume(struct platform_device *pdev)
                codec->hw_write(codec->control_data, data, 2);
        }
 
-       aic3x_dapm_event(codec, codec->suspend_dapm_state);
+       aic3x_set_bias_level(codec, codec->suspend_bias_level);
 
        return 0;
 }
@@ -1020,16 +1052,17 @@ static int aic3x_resume(struct platform_device *pdev)
 static int aic3x_init(struct snd_soc_device *socdev)
 {
        struct snd_soc_codec *codec = socdev->codec;
+       struct aic3x_setup_data *setup = socdev->codec_data;
        int reg, ret = 0;
 
        codec->name = "aic3x";
        codec->owner = THIS_MODULE;
        codec->read = aic3x_read_reg_cache;
        codec->write = aic3x_write;
-       codec->dapm_event = aic3x_dapm_event;
+       codec->set_bias_level = aic3x_set_bias_level;
        codec->dai = &aic3x_dai;
        codec->num_dai = 1;
-       codec->reg_cache_size = sizeof(aic3x_reg);
+       codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
        codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
        if (codec->reg_cache == NULL)
                return -ENOMEM;
@@ -1108,7 +1141,11 @@ static int aic3x_init(struct snd_soc_device *socdev)
        aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
 
        /* off, with power on */
-       aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* setup GPIO functions */
+       aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4);
+       aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4);
 
        aic3x_add_controls(codec);
        aic3x_add_widgets(codec);
@@ -1217,6 +1254,12 @@ static struct i2c_client client_template = {
        .name = "AIC3X",
        .driver = &aic3x_i2c_driver,
 };
+
+static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
+{
+       value[0] = i2c_smbus_read_byte_data(client, value[0]);
+       return (len == 1);
+}
 #endif
 
 static int aic3x_probe(struct platform_device *pdev)
@@ -1251,6 +1294,7 @@ static int aic3x_probe(struct platform_device *pdev)
        if (setup->i2c_address) {
                normal_i2c[0] = setup->i2c_address;
                codec->hw_write = (hw_write_t) i2c_master_send;
+               codec->hw_read = (hw_read_t) aic3x_i2c_read;
                ret = i2c_add_driver(&aic3x_i2c_driver);
                if (ret != 0)
                        printk(KERN_ERR "can't add i2c driver");
@@ -1268,7 +1312,7 @@ static int aic3x_remove(struct platform_device *pdev)
 
        /* power down chip */
        if (codec->control_data)
-               aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3);
+               aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
index d0cdeeb629de5f0a12435f78b5fb2fbe4d4a9a7b..d76c079b86e7b52f148b3a35a49ff0ea2f9a7b8d 100644 (file)
@@ -37,6 +37,8 @@
 #define AIC3X_ASD_INTF_CTRLB           9
 /* Audio overflow status and PLL R value programming register */
 #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11
+/* Audio codec digital filter control register */
+#define AIC3X_CODEC_DFILT_CTRL         12
 
 /* ADC PGA Gain control registers */
 #define LADC_VOL                       15
 #define DACR1_2_RLOPM_VOL              92
 #define LLOPM_CTRL                     86
 #define RLOPM_CTRL                     93
+/* GPIO/IRQ registers */
+#define AIC3X_STICKY_IRQ_FLAGS_REG     96
+#define AIC3X_RT_IRQ_FLAGS_REG         97
+#define AIC3X_GPIO1_REG                        98
+#define AIC3X_GPIO2_REG                        99
+#define AIC3X_GPIOA_REG                        100
+#define AIC3X_GPIOB_REG                        101
 /* Clock generation control register */
 #define AIC3X_CLKGEN_CTRL_REG          102
 
 
 /* PLL registers bitfields */
 #define PLLP_SHIFT             0
+#define PLLQ_SHIFT             3
 #define PLLR_SHIFT             0
 #define PLLJ_SHIFT             2
 #define PLLD_MSB_SHIFT         0
 #define PLLD_LSB_SHIFT         2
 
 /* Clock generation register bits */
+#define CODEC_CLKIN_PLLDIV     0
+#define CODEC_CLKIN_CLKDIV     1
 #define PLL_CLKIN_SHIFT                4
 #define MCLK_SOURCE            0x0
 #define PLL_CLKDIV_SHIFT       0
 /* Default input volume */
 #define DEFAULT_GAIN    0x20
 
+/* GPIO API */
+enum {
+       AIC3X_GPIO1_FUNC_DISABLED               = 0,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
+       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
+       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
+       AIC3X_GPIO1_FUNC_INPUT                  = 8,
+       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
+       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
+       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
+       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
+};
+
+enum {
+       AIC3X_GPIO2_FUNC_DISABLED               = 0,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
+       AIC3X_GPIO2_FUNC_INPUT                  = 3,
+       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
+       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
+       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
+       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
+       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
+};
+
+void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
+int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
+int aic3x_headset_detected(struct snd_soc_codec *codec);
+
 struct aic3x_setup_data {
        unsigned short i2c_address;
+       unsigned int gpio_func[2];
 };
 
-extern struct snd_soc_codec_dai aic3x_dai;
+extern struct snd_soc_dai aic3x_dai;
 extern struct snd_soc_codec_device soc_codec_dev_aic3x;
 
 #endif /* _AIC3X_H */
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
new file mode 100644 (file)
index 0000000..a52d6d9
--- /dev/null
@@ -0,0 +1,852 @@
+/*
+ * uda1380.c - Philips UDA1380 ALSA SoC audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
+ * Improved support for DAPM and audio routing/mixing capabilities,
+ * added TLV support.
+ *
+ * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC
+ * codec model.
+ *
+ * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ * Copyright 2005 Openedhand Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "uda1380.h"
+
+#define UDA1380_VERSION "0.6"
+#define AUDIO_NAME "uda1380"
+
+/*
+ * uda1380 register cache
+ */
+static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = {
+       0x0502, 0x0000, 0x0000, 0x3f3f,
+       0x0202, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0xff00, 0x0000, 0x4800,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x8000, 0x0002, 0x0000,
+};
+
+/*
+ * read uda1380 register cache
+ */
+static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg == UDA1380_RESET)
+               return 0;
+       if (reg >= UDA1380_CACHEREGNUM)
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write uda1380 register cache
+ */
+static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
+       u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= UDA1380_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the UDA1380 register space
+ */
+static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[3];
+
+       /* data is
+        *   data[0] is register offset
+        *   data[1] is MS byte
+        *   data[2] is LS byte
+        */
+       data[0] = reg;
+       data[1] = (value & 0xff00) >> 8;
+       data[2] = value & 0x00ff;
+
+       uda1380_write_reg_cache(codec, reg, value);
+
+       /* the interpolator & decimator regs must only be written when the
+        * codec DAI is active.
+        */
+       if (!codec->active && (reg >= UDA1380_MVOL))
+               return 0;
+       pr_debug("uda1380: hw write %x val %x\n", reg, value);
+       if (codec->hw_write(codec->control_data, data, 3) == 3) {
+               unsigned int val;
+               i2c_master_send(codec->control_data, data, 1);
+               i2c_master_recv(codec->control_data, data, 2);
+               val = (data[0]<<8) | data[1];
+               if (val != value) {
+                       pr_debug("uda1380: READ BACK VAL %x\n",
+                                       (data[0]<<8) | data[1]);
+                       return -EIO;
+               }
+               return 0;
+       } else
+               return -EIO;
+}
+
+#define uda1380_reset(c)       uda1380_write(c, UDA1380_RESET, 0)
+
+/* declarations of ALSA reg_elem_REAL controls */
+static const char *uda1380_deemp[] = {
+       "None",
+       "32kHz",
+       "44.1kHz",
+       "48kHz",
+       "96kHz",
+};
+static const char *uda1380_input_sel[] = {
+       "Line",
+       "Mic + Line R",
+       "Line L",
+       "Mic",
+};
+static const char *uda1380_output_sel[] = {
+       "DAC",
+       "Analog Mixer",
+};
+static const char *uda1380_spf_mode[] = {
+       "Flat",
+       "Minimum1",
+       "Minimum2",
+       "Maximum"
+};
+static const char *uda1380_capture_sel[] = {
+       "ADC",
+       "Digital Mixer"
+};
+static const char *uda1380_sel_ns[] = {
+       "3rd-order",
+       "5th-order"
+};
+static const char *uda1380_mix_control[] = {
+       "off",
+       "PCM only",
+       "before sound processing",
+       "after sound processing"
+};
+static const char *uda1380_sdet_setting[] = {
+       "3200",
+       "4800",
+       "9600",
+       "19200"
+};
+static const char *uda1380_os_setting[] = {
+       "single-speed",
+       "double-speed (no mixing)",
+       "quad-speed (no mixing)"
+};
+
+static const struct soc_enum uda1380_deemp_enum[] = {
+       SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp),
+       SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp),
+};
+static const struct soc_enum uda1380_input_sel_enum =
+       SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel);          /* SEL_MIC, SEL_LNA */
+static const struct soc_enum uda1380_output_sel_enum =
+       SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel);          /* R02_EN_AVC */
+static const struct soc_enum uda1380_spf_enum =
+       SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode);         /* M */
+static const struct soc_enum uda1380_capture_sel_enum =
+       SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel);      /* SEL_SOURCE */
+static const struct soc_enum uda1380_sel_ns_enum =
+       SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns);          /* SEL_NS */
+static const struct soc_enum uda1380_mix_enum =
+       SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control);     /* MIX, MIX_POS */
+static const struct soc_enum uda1380_sdet_enum =
+       SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting);     /* SD_VALUE */
+static const struct soc_enum uda1380_os_enum =
+       SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting);       /* OS */
+
+/*
+ * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB)
+ */
+static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1);
+
+/*
+ * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored),
+ * from -66 dB in 0.5 dB steps (2 dB steps, really) and
+ * from -52 dB in 0.25 dB steps
+ */
+static const unsigned int mvol_tlv[] = {
+       TLV_DB_RANGE_HEAD(3),
+       0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1),
+       16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0),
+       44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0),
+};
+
+/*
+ * from -72 dB in 1.5 dB steps (6 dB steps really),
+ * from -66 dB in 0.75 dB steps (3 dB steps really),
+ * from -60 dB in 0.5 dB steps (2 dB steps really) and
+ * from -46 dB in 0.25 dB steps
+ */
+static const unsigned int vc_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1),
+       8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0),
+       16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0),
+       44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0),
+};
+
+/* from 0 to 6 dB in 2 dB steps if SPF mode != flat */
+static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0);
+
+/* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts
+ * off at 18 dB max) */
+static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0);
+
+/* from -63 to 24 dB in 0.5 dB steps (-128...48) */
+static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1);
+
+/* from 0 to 24 dB in 3 dB steps */
+static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
+
+/* from 0 to 30 dB in 2 dB steps */
+static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0);
+
+static const struct snd_kcontrol_new uda1380_snd_controls[] = {
+       SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv),     /* AVCR, AVCL */
+       SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */
+       SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv),       /* VC2 */
+       SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv),       /* VC1 */
+       SOC_ENUM("Sound Processing Filter", uda1380_spf_enum),                          /* M */
+       SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv),     /* TRL, TRR */
+       SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv),       /* BBL, BBR */
+/**/   SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1),          /* MTM */
+       SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1),             /* MT2 from decimation filter */
+       SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]),            /* DE2 */
+       SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1),              /* MT1, from digital data input */
+       SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]),            /* DE1 */
+       SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0),   /* DA_POL_INV */
+       SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum),                          /* SEL_NS */
+       SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum),             /* MIX_POS, MIX */
+       SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0),                   /* SILENCE, force DAC output to silence */
+       SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0),          /* SDET_ON */
+       SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum),                /* SD_VALUE */
+       SOC_ENUM("Oversampling Input", uda1380_os_enum),                        /* OS */
+       SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv),        /* ML_DEC, MR_DEC */
+/**/   SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1),                /* MT_ADC */
+       SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */
+       SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0),     /* ADCPOL_INV */
+       SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv),   /* VGA_CTRL */
+       SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0),            /* SKIP_DCFIL (before decimator) */
+       SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0),            /* EN_DCFIL (at output of decimator) */
+       SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0),                 /* TODO: enum, see table 62 */
+       SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1),                   /* AGC_LEVEL */
+       /* -5.5, -8, -11.5, -14 dBFS */
+       SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0),
+};
+
+/* add non dapm controls */
+static int uda1380_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                       snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Input mux */
+static const struct snd_kcontrol_new uda1380_input_mux_control =
+       SOC_DAPM_ENUM("Route", uda1380_input_sel_enum);
+
+/* Output mux */
+static const struct snd_kcontrol_new uda1380_output_mux_control =
+       SOC_DAPM_ENUM("Route", uda1380_output_sel_enum);
+
+/* Capture mux */
+static const struct snd_kcontrol_new uda1380_capture_mux_control =
+       SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum);
+
+
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+       SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+               &uda1380_input_mux_control),
+       SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0,
+               &uda1380_output_mux_control),
+       SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
+               &uda1380_capture_mux_control),
+       SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0),
+       SND_SOC_DAPM_INPUT("VINM"),
+       SND_SOC_DAPM_INPUT("VINL"),
+       SND_SOC_DAPM_INPUT("VINR"),
+       SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("VOUTLHP"),
+       SND_SOC_DAPM_OUTPUT("VOUTRHP"),
+       SND_SOC_DAPM_OUTPUT("VOUTL"),
+       SND_SOC_DAPM_OUTPUT("VOUTR"),
+       SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0),
+       SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+       /* output mux */
+       {"HeadPhone Driver", NULL, "Output Mux"},
+       {"VOUTR", NULL, "Output Mux"},
+       {"VOUTL", NULL, "Output Mux"},
+
+       {"Analog Mixer", NULL, "VINR"},
+       {"Analog Mixer", NULL, "VINL"},
+       {"Analog Mixer", NULL, "DAC"},
+
+       {"Output Mux", "DAC", "DAC"},
+       {"Output Mux", "Analog Mixer", "Analog Mixer"},
+
+       /* {"DAC", "Digital Mixer", "I2S" } */
+
+       /* headphone driver */
+       {"VOUTLHP", NULL, "HeadPhone Driver"},
+       {"VOUTRHP", NULL, "HeadPhone Driver"},
+
+       /* input mux */
+       {"Left ADC", NULL, "Input Mux"},
+       {"Input Mux", "Mic", "Mic LNA"},
+       {"Input Mux", "Mic + Line R", "Mic LNA"},
+       {"Input Mux", "Line L", "Left PGA"},
+       {"Input Mux", "Line", "Left PGA"},
+
+       /* right input */
+       {"Right ADC", "Mic + Line R", "Right PGA"},
+       {"Right ADC", "Line", "Right PGA"},
+
+       /* inputs */
+       {"Mic LNA", NULL, "VINM"},
+       {"Left PGA", NULL, "VINL"},
+       {"Right PGA", NULL, "VINR"},
+};
+
+static int uda1380_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+                                 ARRAY_SIZE(uda1380_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int iface;
+
+       /* set up DAI based upon fmt */
+       iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+       iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
+
+       /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= R01_SFORI_I2S | R01_SFORO_I2S;
+               break;
+       case SND_SOC_DAIFMT_LSB:
+               iface |= R01_SFORI_LSB16 | R01_SFORO_I2S;
+               break;
+       case SND_SOC_DAIFMT_MSB:
+               iface |= R01_SFORI_MSB | R01_SFORO_I2S;
+       }
+
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
+               iface |= R01_SIM;
+
+       uda1380_write(codec, UDA1380_IFACE, iface);
+
+       return 0;
+}
+
+/*
+ * Flush reg cache
+ * We can only write the interpolator and decimator registers
+ * when the DAI is being clocked by the CPU DAI. It's up to the
+ * machine and cpu DAI driver to do this before we are called.
+ */
+static int uda1380_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       int reg, reg_start, reg_end, clk;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               reg_start = UDA1380_MVOL;
+               reg_end = UDA1380_MIXER;
+       } else {
+               reg_start = UDA1380_DEC;
+               reg_end = UDA1380_AGC;
+       }
+
+       /* FIXME disable DAC_CLK */
+       clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
+       uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK);
+
+       for (reg = reg_start; reg <= reg_end; reg++) {
+               pr_debug("uda1380: flush reg %x val %x:", reg,
+                               uda1380_read_reg_cache(codec, reg));
+               uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg));
+       }
+
+       /* FIXME enable DAC_CLK */
+       uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK);
+
+       return 0;
+}
+
+static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
+
+       /* set WSPLL power and divider if running from this clock */
+       if (clk & R00_DAC_CLK) {
+               int rate = params_rate(params);
+               u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+               clk &= ~0x3; /* clear SEL_LOOP_DIV */
+               switch (rate) {
+               case 6250 ... 12500:
+                       clk |= 0x0;
+                       break;
+               case 12501 ... 25000:
+                       clk |= 0x1;
+                       break;
+               case 25001 ... 50000:
+                       clk |= 0x2;
+                       break;
+               case 50001 ... 100000:
+                       clk |= 0x3;
+                       break;
+               }
+               uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm);
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               clk |= R00_EN_DAC | R00_EN_INT;
+       else
+               clk |= R00_EN_ADC | R00_EN_DEC;
+
+       uda1380_write(codec, UDA1380_CLK, clk);
+       return 0;
+}
+
+static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
+
+       /* shut down WSPLL power if running from this clock */
+       if (clk & R00_DAC_CLK) {
+               u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+               uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm);
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               clk &= ~(R00_EN_DAC | R00_EN_INT);
+       else
+               clk &= ~(R00_EN_ADC | R00_EN_DEC);
+
+       uda1380_write(codec, UDA1380_CLK, clk);
+}
+
+static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM;
+
+       /* FIXME: mute(codec,0) is called when the magician clock is already
+        * set to WSPLL, but for some unknown reason writing to interpolator
+        * registers works only when clocked by SYSCLK */
+       u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
+       uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk);
+       if (mute)
+               uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM);
+       else
+               uda1380_write(codec, UDA1380_DEEMP, mute_reg);
+       uda1380_write(codec, UDA1380_CLK, clk);
+       return 0;
+}
+
+static int uda1380_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
+               break;
+       case SND_SOC_BIAS_OFF:
+               uda1380_write(codec, UDA1380_PM, 0x0);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+                      SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+                      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_dai uda1380_dai[] = {
+{
+       .name = "UDA1380",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = UDA1380_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = UDA1380_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = {
+               .hw_params = uda1380_pcm_hw_params,
+               .shutdown = uda1380_pcm_shutdown,
+               .prepare = uda1380_pcm_prepare,
+       },
+       .dai_ops = {
+               .digital_mute = uda1380_mute,
+               .set_fmt = uda1380_set_dai_fmt,
+       },
+},
+{ /* playback only - dual interface */
+       .name = "UDA1380",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = UDA1380_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = {
+               .hw_params = uda1380_pcm_hw_params,
+               .shutdown = uda1380_pcm_shutdown,
+               .prepare = uda1380_pcm_prepare,
+       },
+       .dai_ops = {
+               .digital_mute = uda1380_mute,
+               .set_fmt = uda1380_set_dai_fmt,
+       },
+},
+{ /* capture only - dual interface*/
+       .name = "UDA1380",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = UDA1380_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = {
+               .hw_params = uda1380_pcm_hw_params,
+               .shutdown = uda1380_pcm_shutdown,
+               .prepare = uda1380_pcm_prepare,
+       },
+       .dai_ops = {
+               .set_fmt = uda1380_set_dai_fmt,
+       },
+},
+};
+EXPORT_SYMBOL_GPL(uda1380_dai);
+
+static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int uda1380_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u8 data[2];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+       uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       uda1380_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+/*
+ * initialise the UDA1380 driver
+ * register mixer and dsp interfaces with the kernel
+ */
+static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+
+       codec->name = "UDA1380";
+       codec->owner = THIS_MODULE;
+       codec->read = uda1380_read_reg_cache;
+       codec->write = uda1380_write;
+       codec->set_bias_level = uda1380_set_bias_level;
+       codec->dai = uda1380_dai;
+       codec->num_dai = ARRAY_SIZE(uda1380_dai);
+       codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg),
+                                  GFP_KERNEL);
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+       codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
+       codec->reg_cache_step = 1;
+       uda1380_reset(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               pr_err("uda1380: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* power on device */
+       uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       /* set clock input */
+       switch (dac_clk) {
+       case UDA1380_DAC_CLK_SYSCLK:
+               uda1380_write(codec, UDA1380_CLK, 0);
+               break;
+       case UDA1380_DAC_CLK_WSPLL:
+               uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
+               break;
+       }
+
+       /* uda1380 init */
+       uda1380_add_controls(codec);
+       uda1380_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               pr_err("uda1380: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+static struct snd_soc_device *uda1380_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+#define I2C_DRIVERID_UDA1380 0xfefe /* liam -  need a proper id */
+
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver uda1380_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+
+static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = uda1380_socdev;
+       struct uda1380_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               pr_err("uda1380: failed to attach codec at addr %x\n", addr);
+               goto err;
+       }
+
+       ret = uda1380_init(socdev, setup->dac_clk);
+       if (ret < 0) {
+               pr_err("uda1380: failed to initialise UDA1380\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int uda1380_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int uda1380_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, uda1380_codec_probe);
+}
+
+static struct i2c_driver uda1380_i2c_driver = {
+       .driver = {
+               .name =  "UDA1380 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .id =             I2C_DRIVERID_UDA1380,
+       .attach_adapter = uda1380_i2c_attach,
+       .detach_client =  uda1380_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "UDA1380",
+       .driver = &uda1380_i2c_driver,
+};
+#endif
+
+static int uda1380_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct uda1380_setup_data *setup;
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       uda1380_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = i2c_add_driver(&uda1380_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+       /* Add other interfaces here */
+#endif
+       return ret;
+}
+
+/* power down chip */
+static int uda1380_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&uda1380_i2c_driver);
+#endif
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_uda1380 = {
+       .probe =        uda1380_probe,
+       .remove =       uda1380_remove,
+       .suspend =      uda1380_suspend,
+       .resume =       uda1380_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
+
+MODULE_AUTHOR("Giorgio Padrin");
+MODULE_DESCRIPTION("Audio support for codec Philips UDA1380");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h
new file mode 100644 (file)
index 0000000..50c603e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Audio support for Philips UDA1380
+ *
+ * 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.
+ *
+ * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org>
+ */
+
+#ifndef _UDA1380_H
+#define _UDA1380_H
+
+#define UDA1380_CLK    0x00
+#define UDA1380_IFACE  0x01
+#define UDA1380_PM     0x02
+#define UDA1380_AMIX   0x03
+#define UDA1380_HP     0x04
+#define UDA1380_MVOL   0x10
+#define UDA1380_MIXVOL 0x11
+#define UDA1380_MODE   0x12
+#define UDA1380_DEEMP  0x13
+#define UDA1380_MIXER  0x14
+#define UDA1380_INTSTAT        0x18
+#define UDA1380_DEC    0x20
+#define UDA1380_PGA    0x21
+#define UDA1380_ADC    0x22
+#define UDA1380_AGC    0x23
+#define UDA1380_DECSTAT        0x28
+#define UDA1380_RESET  0x7f
+
+#define UDA1380_CACHEREGNUM 0x24
+
+/* Register flags */
+#define R00_EN_ADC     0x0800
+#define R00_EN_DEC     0x0400
+#define R00_EN_DAC     0x0200
+#define R00_EN_INT     0x0100
+#define R00_DAC_CLK    0x0010
+#define R01_SFORI_I2S   0x0000
+#define R01_SFORI_LSB16 0x0100
+#define R01_SFORI_LSB18 0x0200
+#define R01_SFORI_LSB20 0x0300
+#define R01_SFORI_MSB   0x0500
+#define R01_SFORI_MASK  0x0700
+#define R01_SFORO_I2S   0x0000
+#define R01_SFORO_LSB16 0x0001
+#define R01_SFORO_LSB18 0x0002
+#define R01_SFORO_LSB20 0x0003
+#define R01_SFORO_LSB24 0x0004
+#define R01_SFORO_MSB   0x0005
+#define R01_SFORO_MASK  0x0007
+#define R01_SEL_SOURCE  0x0040
+#define R01_SIM                0x0010
+#define R02_PON_PLL    0x8000
+#define R02_PON_HP     0x2000
+#define R02_PON_DAC    0x0400
+#define R02_PON_BIAS   0x0100
+#define R02_EN_AVC     0x0080
+#define R02_PON_AVC    0x0040
+#define R02_PON_LNA    0x0010
+#define R02_PON_PGAL   0x0008
+#define R02_PON_ADCL   0x0004
+#define R02_PON_PGAR   0x0002
+#define R02_PON_ADCR   0x0001
+#define R13_MTM                0x4000
+#define R14_SILENCE    0x0080
+#define R14_SDET_ON    0x0040
+#define R21_MT_ADC     0x8000
+#define R22_SEL_LNA    0x0008
+#define R22_SEL_MIC    0x0004
+#define R22_SKIP_DCFIL 0x0002
+#define R23_AGC_EN     0x0001
+
+struct uda1380_setup_data {
+       unsigned short i2c_address;
+       int            dac_clk;
+#define UDA1380_DAC_CLK_SYSCLK 0
+#define UDA1380_DAC_CLK_WSPLL  1
+};
+
+#define UDA1380_DAI_DUPLEX     0 /* playback and capture on single DAI */
+#define UDA1380_DAI_PLAYBACK   1 /* playback DAI */
+#define UDA1380_DAI_CAPTURE    2 /* capture DAI */
+
+extern struct snd_soc_dai uda1380_dai[3];
+extern struct snd_soc_codec_device soc_codec_dev_uda1380;
+
+#endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
new file mode 100644 (file)
index 0000000..67325fd
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+ * wm8510.c  --  WM8510 ALSA Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "wm8510.h"
+
+#define AUDIO_NAME "wm8510"
+#define WM8510_VERSION "0.6"
+
+struct snd_soc_codec_device soc_codec_dev_wm8510;
+
+/*
+ * wm8510 register cache
+ * We can't read the WM8510 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ */
+static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0050, 0x0000, 0x0140, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x00ff,
+       0x0000, 0x0000, 0x0100, 0x00ff,
+       0x0000, 0x0000, 0x012c, 0x002c,
+       0x002c, 0x002c, 0x002c, 0x0000,
+       0x0032, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0038, 0x000b, 0x0032, 0x0000,
+       0x0008, 0x000c, 0x0093, 0x00e9,
+       0x0000, 0x0000, 0x0000, 0x0000,
+       0x0003, 0x0010, 0x0000, 0x0000,
+       0x0000, 0x0002, 0x0001, 0x0000,
+       0x0000, 0x0000, 0x0039, 0x0000,
+       0x0001,
+};
+
+/*
+ * read wm8510 register cache
+ */
+static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg == WM8510_RESET)
+               return 0;
+       if (reg >= WM8510_CACHEREGNUM)
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write wm8510 register cache
+ */
+static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec,
+       u16 reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg >= WM8510_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the WM8510 register space
+ */
+static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D9 WM8510 register offset
+        *   D8...D0 register data
+        */
+       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+       data[1] = value & 0x00ff;
+
+       wm8510_write_reg_cache(codec, reg, value);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define wm8510_reset(c)        wm8510_write(c, WM8510_RESET, 0)
+
+static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
+static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
+static const char *wm8510_alc[] = { "ALC", "Limiter" };
+
+static const struct soc_enum wm8510_enum[] = {
+       SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */
+       SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */
+       SOC_ENUM_SINGLE(WM8510_DAC,  4, 4, wm8510_deemp),
+       SOC_ENUM_SINGLE(WM8510_ALC3,  8, 2, wm8510_alc),
+};
+
+static const struct snd_kcontrol_new wm8510_snd_controls[] = {
+
+SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0),
+
+SOC_ENUM("DAC Companding", wm8510_enum[1]),
+SOC_ENUM("ADC Companding", wm8510_enum[0]),
+
+SOC_ENUM("Playback De-emphasis", wm8510_enum[2]),
+SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0),
+
+SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0),
+
+SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0),
+SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0),
+SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0),
+
+SOC_SINGLE("Capture Volume", WM8510_ADCVOL,  0, 127, 0),
+
+SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1,  8, 1, 0),
+SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1,  4, 15, 0),
+SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1,  0, 15, 0),
+
+SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2,  4, 7, 0),
+SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2,  0, 15, 0),
+
+SOC_SINGLE("ALC Enable Switch", WM8510_ALC1,  8, 1, 0),
+SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1,  3, 7, 0),
+SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1,  0, 7, 0),
+
+SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2,  8, 1, 0),
+SOC_SINGLE("ALC Capture Hold", WM8510_ALC2,  4, 7, 0),
+SOC_SINGLE("ALC Capture Target", WM8510_ALC2,  0, 15, 0),
+
+SOC_ENUM("ALC Capture Mode", wm8510_enum[3]),
+SOC_SINGLE("ALC Capture Decay", WM8510_ALC3,  4, 15, 0),
+SOC_SINGLE("ALC Capture Attack", WM8510_ALC3,  0, 15, 0),
+
+SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE,  3, 1, 0),
+SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE,  0, 7, 0),
+
+SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA,  7, 1, 0),
+SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA,  0, 63, 0),
+
+SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL,  7, 1, 0),
+SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL,  6, 1, 1),
+SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL,  0, 63, 0),
+SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0),
+
+SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST,  8, 1, 0),
+SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1),
+};
+
+/* add non dapm controls */
+static int wm8510_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                               snd_soc_cnew(&wm8510_snd_controls[i], codec,
+                                       NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Speaker Output Mixer */
+static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0),
+};
+
+/* Mono Output Mixer */
+static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0),
+SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0),
+SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8510_boost_controls[] = {
+SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 0),
+SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0),
+SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0),
+};
+
+static const struct snd_kcontrol_new wm8510_micpga_controls[] = {
+SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0),
+SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0),
+SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0,
+       &wm8510_speaker_mixer_controls[0],
+       ARRAY_SIZE(wm8510_speaker_mixer_controls)),
+SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0,
+       &wm8510_mono_mixer_controls[0],
+       ARRAY_SIZE(wm8510_mono_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0),
+SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
+                &wm8510_micpga_controls[0],
+                ARRAY_SIZE(wm8510_micpga_controls)),
+SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
+       &wm8510_boost_controls[0],
+       ARRAY_SIZE(wm8510_boost_controls)),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0),
+
+SND_SOC_DAPM_INPUT("MICN"),
+SND_SOC_DAPM_INPUT("MICP"),
+SND_SOC_DAPM_INPUT("AUX"),
+SND_SOC_DAPM_OUTPUT("MONOOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Mono output mixer */
+       {"Mono Mixer", "PCM Playback Switch", "DAC"},
+       {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
+       {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+       /* Speaker output mixer */
+       {"Speaker Mixer", "PCM Playback Switch", "DAC"},
+       {"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
+       {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
+
+       /* Outputs */
+       {"Mono Out", NULL, "Mono Mixer"},
+       {"MONOOUT", NULL, "Mono Out"},
+       {"SpkN Out", NULL, "Speaker Mixer"},
+       {"SpkP Out", NULL, "Speaker Mixer"},
+       {"SPKOUTN", NULL, "SpkN Out"},
+       {"SPKOUTP", NULL, "SpkP Out"},
+
+       /* Microphone PGA */
+       {"Mic PGA", "MICN Switch", "MICN"},
+       {"Mic PGA", "MICP Switch", "MICP"},
+       { "Mic PGA", "AUX Switch", "Aux Input" },
+
+       /* Boost Mixer */
+       {"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
+       {"Boost Mixer", "Mic Volume", "MICP"},
+       {"Boost Mixer", "Aux Volume", "Aux Input"},
+
+       {"ADC", NULL, "Boost Mixer"},
+};
+
+static int wm8510_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets,
+                                 ARRAY_SIZE(wm8510_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+struct pll_ {
+       unsigned int pre_div:4; /* prescale - 1 */
+       unsigned int n:4;
+       unsigned int k;
+};
+
+static struct pll_ pll_div;
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 24) * 10)
+
+static void pll_factors(unsigned int target, unsigned int source)
+{
+       unsigned long long Kpart;
+       unsigned int K, Ndiv, Nmod;
+
+       Ndiv = target / source;
+       if (Ndiv < 6) {
+               source >>= 1;
+               pll_div.pre_div = 1;
+               Ndiv = target / source;
+       } else
+               pll_div.pre_div = 0;
+
+       if ((Ndiv < 6) || (Ndiv > 12))
+               printk(KERN_WARNING
+                       "WM8510 N value %d outwith recommended range!d\n",
+                       Ndiv);
+
+       pll_div.n = Ndiv;
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       /* Check if we need to round */
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       K /= 10;
+
+       pll_div.k = K;
+}
+
+static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       if (freq_in == 0 || freq_out == 0) {
+               /* Clock CODEC directly from MCLK */
+               reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
+               wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff);
+
+               /* Turn off PLL */
+               reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
+               wm8510_write(codec, WM8510_POWER1, reg & 0x1df);
+               return 0;
+       }
+
+       pll_factors(freq_out*8, freq_in);
+
+       wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
+       wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
+       wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
+       wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
+       reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
+       wm8510_write(codec, WM8510_POWER1, reg | 0x020);
+
+       /* Run CODEC from PLL instead of MCLK */
+       reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
+       wm8510_write(codec, WM8510_CLOCK, reg | 0x100);
+
+       return 0;
+}
+
+/*
+ * Configure WM8510 clock dividers.
+ */
+static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+               int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       switch (div_id) {
+       case WM8510_OPCLKDIV:
+               reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf;
+               wm8510_write(codec, WM8510_GPIO, reg | div);
+               break;
+       case WM8510_MCLKDIV:
+               reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f;
+               wm8510_write(codec, WM8510_CLOCK, reg | div);
+               break;
+       case WM8510_ADCCLK:
+               reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7;
+               wm8510_write(codec, WM8510_ADC, reg | div);
+               break;
+       case WM8510_DACCLK:
+               reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7;
+               wm8510_write(codec, WM8510_DAC, reg | div);
+               break;
+       case WM8510_BCLKDIV:
+               reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3;
+               wm8510_write(codec, WM8510_CLOCK, reg | div);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = 0;
+       u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clk |= 0x0001;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= 0x0010;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= 0x0008;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= 0x00018;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= 0x0180;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= 0x0100;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= 0x0080;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8510_write(codec, WM8510_IFACE, iface);
+       wm8510_write(codec, WM8510_CLOCK, clk);
+       return 0;
+}
+
+static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
+       u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= 0x0020;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= 0x0040;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= 0x0060;
+               break;
+       }
+
+       /* filter coefficient */
+       switch (params_rate(params)) {
+       case SNDRV_PCM_RATE_8000:
+               adn |= 0x5 << 1;
+               break;
+       case SNDRV_PCM_RATE_11025:
+               adn |= 0x4 << 1;
+               break;
+       case SNDRV_PCM_RATE_16000:
+               adn |= 0x3 << 1;
+               break;
+       case SNDRV_PCM_RATE_22050:
+               adn |= 0x2 << 1;
+               break;
+       case SNDRV_PCM_RATE_32000:
+               adn |= 0x1 << 1;
+               break;
+       case SNDRV_PCM_RATE_44100:
+       case SNDRV_PCM_RATE_48000:
+               break;
+       }
+
+       wm8510_write(codec, WM8510_IFACE, iface);
+       wm8510_write(codec, WM8510_ADD, adn);
+       return 0;
+}
+
+static int wm8510_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf;
+
+       if (mute)
+               wm8510_write(codec, WM8510_DAC, mute_reg | 0x40);
+       else
+               wm8510_write(codec, WM8510_DAC, mute_reg);
+       return 0;
+}
+
+/* liam need to make this lower power with dapm */
+static int wm8510_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               wm8510_write(codec, WM8510_POWER1, 0x1ff);
+               wm8510_write(codec, WM8510_POWER2, 0x1ff);
+               wm8510_write(codec, WM8510_POWER3, 0x1ff);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+       case SND_SOC_BIAS_STANDBY:
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* everything off, dac mute, inactive */
+               wm8510_write(codec, WM8510_POWER1, 0x0);
+               wm8510_write(codec, WM8510_POWER2, 0x0);
+               wm8510_write(codec, WM8510_POWER3, 0x0);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai wm8510_dai = {
+       .name = "WM8510 HiFi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8510_RATES,
+               .formats = WM8510_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8510_RATES,
+               .formats = WM8510_FORMATS,},
+       .ops = {
+               .hw_params = wm8510_pcm_hw_params,
+       },
+       .dai_ops = {
+               .digital_mute = wm8510_mute,
+               .set_fmt = wm8510_set_dai_fmt,
+               .set_clkdiv = wm8510_set_dai_clkdiv,
+               .set_pll = wm8510_set_dai_pll,
+       },
+};
+EXPORT_SYMBOL_GPL(wm8510_dai);
+
+static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8510_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u8 data[2];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
+               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+       wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8510_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+/*
+ * initialise the WM8510 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8510_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+
+       codec->name = "WM8510";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8510_read_reg_cache;
+       codec->write = wm8510_write;
+       codec->set_bias_level = wm8510_set_bias_level;
+       codec->dai = &wm8510_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
+       codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
+
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       wm8510_reset(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8510: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* power on device */
+       wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8510_add_controls(codec);
+       wm8510_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8510: failed to register card\n");
+               goto card_err;
+       }
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+static struct snd_soc_device *wm8510_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+/*
+ * WM8510 2 wire address is 0x1a
+ */
+#define I2C_DRIVERID_WM8510 0xfefe /* liam -  need a proper id */
+
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8510_i2c_driver;
+static struct i2c_client client_template;
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+
+static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = wm8510_socdev;
+       struct wm8510_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               pr_err("failed to attach codec at addr %x\n", addr);
+               goto err;
+       }
+
+       ret = wm8510_init(socdev);
+       if (ret < 0) {
+               pr_err("failed to initialise WM8510\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int wm8510_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int wm8510_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, wm8510_codec_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver wm8510_i2c_driver = {
+       .driver = {
+               .name = "WM8510 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .id =             I2C_DRIVERID_WM8510,
+       .attach_adapter = wm8510_i2c_attach,
+       .detach_client =  wm8510_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "WM8510",
+       .driver = &wm8510_i2c_driver,
+};
+#endif
+
+static int wm8510_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct wm8510_setup_data *setup;
+       struct snd_soc_codec *codec;
+       int ret = 0;
+
+       pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       wm8510_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = i2c_add_driver(&wm8510_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+       /* Add other interfaces here */
+#endif
+       return ret;
+}
+
+/* power down chip */
+static int wm8510_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8510_i2c_driver);
+#endif
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8510 = {
+       .probe =        wm8510_probe,
+       .remove =       wm8510_remove,
+       .suspend =      wm8510_suspend,
+       .resume =       wm8510_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
+
+MODULE_DESCRIPTION("ASoC WM8510 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h
new file mode 100644 (file)
index 0000000..f5d2e42
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * wm8510.h  --  WM8510 Soc Audio driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8510_H
+#define _WM8510_H
+
+/* WM8510 register space */
+
+#define WM8510_RESET           0x0
+#define WM8510_POWER1          0x1
+#define WM8510_POWER2          0x2
+#define WM8510_POWER3          0x3
+#define WM8510_IFACE           0x4
+#define WM8510_COMP                    0x5
+#define WM8510_CLOCK           0x6
+#define WM8510_ADD                     0x7
+#define WM8510_GPIO                    0x8
+#define WM8510_DAC                     0xa
+#define WM8510_DACVOL          0xb
+#define WM8510_ADC                     0xe
+#define WM8510_ADCVOL          0xf
+#define WM8510_EQ1                     0x12
+#define WM8510_EQ2                     0x13
+#define WM8510_EQ3                     0x14
+#define WM8510_EQ4                     0x15
+#define WM8510_EQ5                     0x16
+#define WM8510_DACLIM1         0x18
+#define WM8510_DACLIM2         0x19
+#define WM8510_NOTCH1          0x1b
+#define WM8510_NOTCH2          0x1c
+#define WM8510_NOTCH3          0x1d
+#define WM8510_NOTCH4          0x1e
+#define WM8510_ALC1                    0x20
+#define WM8510_ALC2                    0x21
+#define WM8510_ALC3                    0x22
+#define WM8510_NGATE           0x23
+#define WM8510_PLLN                    0x24
+#define WM8510_PLLK1           0x25
+#define WM8510_PLLK2           0x26
+#define WM8510_PLLK3           0x27
+#define WM8510_ATTEN           0x28
+#define WM8510_INPUT           0x2c
+#define WM8510_INPPGA          0x2d
+#define WM8510_ADCBOOST                0x2f
+#define WM8510_OUTPUT          0x31
+#define WM8510_SPKMIX          0x32
+#define WM8510_SPKVOL          0x36
+#define WM8510_MONOMIX         0x38
+
+#define WM8510_CACHEREGNUM     57
+
+/* Clock divider Id's */
+#define WM8510_OPCLKDIV                0
+#define WM8510_MCLKDIV         1
+#define WM8510_ADCCLK          2
+#define WM8510_DACCLK          3
+#define WM8510_BCLKDIV         4
+
+/* DAC clock dividers */
+#define WM8510_DACCLK_F2       (1 << 3)
+#define WM8510_DACCLK_F4       (0 << 3)
+
+/* ADC clock dividers */
+#define WM8510_ADCCLK_F2       (1 << 3)
+#define WM8510_ADCCLK_F4       (0 << 3)
+
+/* PLL Out dividers */
+#define WM8510_OPCLKDIV_1      (0 << 4)
+#define WM8510_OPCLKDIV_2      (1 << 4)
+#define WM8510_OPCLKDIV_3      (2 << 4)
+#define WM8510_OPCLKDIV_4      (3 << 4)
+
+/* BCLK clock dividers */
+#define WM8510_BCLKDIV_1       (0 << 2)
+#define WM8510_BCLKDIV_2       (1 << 2)
+#define WM8510_BCLKDIV_4       (2 << 2)
+#define WM8510_BCLKDIV_8       (3 << 2)
+#define WM8510_BCLKDIV_16      (4 << 2)
+#define WM8510_BCLKDIV_32      (5 << 2)
+
+/* MCLK clock dividers */
+#define WM8510_MCLKDIV_1       (0 << 5)
+#define WM8510_MCLKDIV_1_5     (1 << 5)
+#define WM8510_MCLKDIV_2       (2 << 5)
+#define WM8510_MCLKDIV_3       (3 << 5)
+#define WM8510_MCLKDIV_4       (4 << 5)
+#define WM8510_MCLKDIV_6       (5 << 5)
+#define WM8510_MCLKDIV_8       (6 << 5)
+#define WM8510_MCLKDIV_12      (7 << 5)
+
+struct wm8510_setup_data {
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_dai wm8510_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8510;
+
+#endif
index 0cf9265fca8fb54ef9c66d1704a896738b60d227..369d39c3f745d9d441ff23d253afaa51dc36aefb 100644 (file)
 #define AUDIO_NAME "wm8731"
 #define WM8731_VERSION "0.13"
 
-/*
- * Debug
- */
-
-#define WM8731_DEBUG 0
-
-#ifdef WM8731_DEBUG
-#define dbg(format, arg...) \
-       printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) \
-       printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
-#define info(format, arg...) \
-       printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
-#define warn(format, arg...) \
-       printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
-
 struct snd_soc_codec_device soc_codec_dev_wm8731;
 
 /* codec private data */
@@ -193,7 +174,7 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
 SND_SOC_DAPM_INPUT("LLINEIN"),
 };
 
-static const char *intercon[][3] = {
+static const struct snd_soc_dapm_route intercon[] = {
        /* output mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -214,22 +195,14 @@ static const char *intercon[][3] = {
        {"Line Input", NULL, "LLINEIN"},
        {"Line Input", NULL, "RLINEIN"},
        {"Mic Bias", NULL, "MICIN"},
-
-       /* terminator */
-       {NULL, NULL, NULL},
 };
 
 static int wm8731_add_widgets(struct snd_soc_codec *codec)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
+                                 ARRAY_SIZE(wm8731_dapm_widgets));
 
-       /* set up audio path interconnects */
-       for (i = 0; intercon[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, intercon[i][0],
-                       intercon[i][1], intercon[i][2]);
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
        snd_soc_dapm_new_widgets(codec);
        return 0;
@@ -345,7 +318,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream)
        }
 }
 
-static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute)
+static int wm8731_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
@@ -357,7 +330,7 @@ static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute)
        return 0;
 }
 
-static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -376,7 +349,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
 }
 
 
-static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -435,29 +408,29 @@ static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return 0;
 }
 
-static int wm8731_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm8731_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
 {
        u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
 
-       switch (event) {
-       case SNDRV_CTL_POWER_D0: /* full On */
+       switch (level) {
+       case SND_SOC_BIAS_ON:
                /* vref/mid, osc on, dac unmute */
                wm8731_write(codec, WM8731_PWR, reg);
                break;
-       case SNDRV_CTL_POWER_D1: /* partial On */
-       case SNDRV_CTL_POWER_D2: /* partial On */
+       case SND_SOC_BIAS_PREPARE:
                break;
-       case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+       case SND_SOC_BIAS_STANDBY:
                /* everything off except vref/vmid, */
                wm8731_write(codec, WM8731_PWR, reg | 0x0040);
                break;
-       case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+       case SND_SOC_BIAS_OFF:
                /* everything off, dac mute, inactive */
                wm8731_write(codec, WM8731_ACTIVE, 0x0);
                wm8731_write(codec, WM8731_PWR, 0xffff);
                break;
        }
-       codec->dapm_state = event;
+       codec->bias_level = level;
        return 0;
 }
 
@@ -470,7 +443,7 @@ static int wm8731_dapm_event(struct snd_soc_codec *codec, int event)
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-struct snd_soc_codec_dai wm8731_dai = {
+struct snd_soc_dai wm8731_dai = {
        .name = "WM8731",
        .playback = {
                .stream_name = "Playback",
@@ -503,7 +476,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
        struct snd_soc_codec *codec = socdev->codec;
 
        wm8731_write(codec, WM8731_ACTIVE, 0x0);
-       wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+       wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
@@ -521,8 +494,8 @@ static int wm8731_resume(struct platform_device *pdev)
                data[1] = cache[i] & 0x00ff;
                codec->hw_write(codec->control_data, data, 2);
        }
-       wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
-       wm8731_dapm_event(codec, codec->suspend_dapm_state);
+       wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8731_set_bias_level(codec, codec->suspend_bias_level);
        return 0;
 }
 
@@ -539,10 +512,10 @@ static int wm8731_init(struct snd_soc_device *socdev)
        codec->owner = THIS_MODULE;
        codec->read = wm8731_read_reg_cache;
        codec->write = wm8731_write;
-       codec->dapm_event = wm8731_dapm_event;
+       codec->set_bias_level = wm8731_set_bias_level;
        codec->dai = &wm8731_dai;
        codec->num_dai = 1;
-       codec->reg_cache_size = sizeof(wm8731_reg);
+       codec->reg_cache_size = ARRAY_SIZE(wm8731_reg);
        codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);
        if (codec->reg_cache == NULL)
                return -ENOMEM;
@@ -557,7 +530,7 @@ static int wm8731_init(struct snd_soc_device *socdev)
        }
 
        /* power on device */
-       wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* set the update bits */
        reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
@@ -632,13 +605,13 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 
        ret = i2c_attach_client(i2c);
        if (ret < 0) {
-               err("failed to attach codec at addr %x\n", addr);
+               pr_err("failed to attach codec at addr %x\n", addr);
                goto err;
        }
 
        ret = wm8731_init(socdev);
        if (ret < 0) {
-               err("failed to initialise WM8731\n");
+               pr_err("failed to initialise WM8731\n");
                goto err;
        }
        return ret;
@@ -689,7 +662,7 @@ static int wm8731_probe(struct platform_device *pdev)
        struct wm8731_priv *wm8731;
        int ret = 0;
 
-       info("WM8731 Audio Codec %s", WM8731_VERSION);
+       pr_info("WM8731 Audio Codec %s", WM8731_VERSION);
 
        setup = socdev->codec_data;
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
@@ -730,7 +703,7 @@ static int wm8731_remove(struct platform_device *pdev)
        struct snd_soc_codec *codec = socdev->codec;
 
        if (codec->control_data)
-               wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+               wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
index 5bcab6a7afb4f8c2a760637383201944c87da565..99f2e3c60e3331c6802318b636ff709fc4796518 100644 (file)
@@ -38,7 +38,7 @@ struct wm8731_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_codec_dai wm8731_dai;
+extern struct snd_soc_dai wm8731_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8731;
 
 #endif
index 16cd5d4d5ad97108443d6bc1e51db727c282b5d4..e23cb09f0d1499ef76a1fd50790b14e4aef1500a 100644 (file)
 #define AUDIO_NAME "WM8750"
 #define WM8750_VERSION "0.12"
 
-/*
- * Debug
- */
-
-#define WM8750_DEBUG 0
-
-#ifdef WM8750_DEBUG
-#define dbg(format, arg...) \
-       printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) \
-       printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
-#define info(format, arg...) \
-       printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
-#define warn(format, arg...) \
-       printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
-
 /* codec private data */
 struct wm8750_priv {
        unsigned int sysclk;
@@ -378,7 +359,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("RINPUT3"),
 };
 
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
        /* left mixer */
        {"Left Mixer", "Playback Switch", "Left DAC"},
        {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
@@ -470,22 +451,14 @@ static const char *audio_map[][3] = {
        /* ADC */
        {"Left ADC", NULL, "Left ADC Mux"},
        {"Right ADC", NULL, "Right ADC Mux"},
-
-       /* terminator */
-       {NULL, NULL, NULL},
 };
 
 static int wm8750_add_widgets(struct snd_soc_codec *codec)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+                                 ARRAY_SIZE(wm8750_dapm_widgets));
 
-       /* set up audio path audio_mapnects */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        snd_soc_dapm_new_widgets(codec);
        return 0;
@@ -563,7 +536,7 @@ static inline int get_coeff(int mclk, int rate)
        return -EINVAL;
 }
 
-static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -581,7 +554,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
        return -EINVAL;
 }
 
-static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -674,7 +647,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute)
+static int wm8750_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7;
@@ -686,29 +659,29 @@ static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute)
        return 0;
 }
 
-static int wm8750_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm8750_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
 {
        u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e;
 
-       switch (event) {
-       case SNDRV_CTL_POWER_D0: /* full On */
+       switch (level) {
+       case SND_SOC_BIAS_ON:
                /* set vmid to 50k and unmute dac */
                wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
                break;
-       case SNDRV_CTL_POWER_D1: /* partial On */
-       case SNDRV_CTL_POWER_D2: /* partial On */
+       case SND_SOC_BIAS_PREPARE:
                /* set vmid to 5k for quick power up */
                wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
                break;
-       case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+       case SND_SOC_BIAS_STANDBY:
                /* mute dac and set vmid to 500k, enable VREF */
                wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
                break;
-       case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+       case SND_SOC_BIAS_OFF:
                wm8750_write(codec, WM8750_PWR1, 0x0001);
                break;
        }
-       codec->dapm_state = event;
+       codec->bias_level = level;
        return 0;
 }
 
@@ -719,7 +692,7 @@ static int wm8750_dapm_event(struct snd_soc_codec *codec, int event)
 #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-struct snd_soc_codec_dai wm8750_dai = {
+struct snd_soc_dai wm8750_dai = {
        .name = "WM8750",
        .playback = {
                .stream_name = "Playback",
@@ -748,7 +721,7 @@ static void wm8750_work(struct work_struct *work)
 {
        struct snd_soc_codec *codec =
                container_of(work, struct snd_soc_codec, delayed_work.work);
-       wm8750_dapm_event(codec, codec->dapm_state);
+       wm8750_set_bias_level(codec, codec->bias_level);
 }
 
 static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
@@ -756,7 +729,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->codec;
 
-       wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+       wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
@@ -777,12 +750,12 @@ static int wm8750_resume(struct platform_device *pdev)
                codec->hw_write(codec->control_data, data, 2);
        }
 
-       wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* charge wm8750 caps */
-       if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
-               wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
-               codec->dapm_state = SNDRV_CTL_POWER_D0;
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+               wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+               codec->bias_level = SND_SOC_BIAS_ON;
                schedule_delayed_work(&codec->delayed_work,
                                        msecs_to_jiffies(1000));
        }
@@ -803,10 +776,10 @@ static int wm8750_init(struct snd_soc_device *socdev)
        codec->owner = THIS_MODULE;
        codec->read = wm8750_read_reg_cache;
        codec->write = wm8750_write;
-       codec->dapm_event = wm8750_dapm_event;
+       codec->set_bias_level = wm8750_set_bias_level;
        codec->dai = &wm8750_dai;
        codec->num_dai = 1;
-       codec->reg_cache_size = sizeof(wm8750_reg);
+       codec->reg_cache_size = ARRAY_SIZE(wm8750_reg);
        codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL);
        if (codec->reg_cache == NULL)
                return -ENOMEM;
@@ -821,8 +794,8 @@ static int wm8750_init(struct snd_soc_device *socdev)
        }
 
        /* charge output caps */
-       wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2);
-       codec->dapm_state = SNDRV_CTL_POWER_D3hot;
+       wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+       codec->bias_level = SND_SOC_BIAS_STANDBY;
        schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
 
        /* set the update bits */
@@ -904,13 +877,13 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 
        ret = i2c_attach_client(i2c);
        if (ret < 0) {
-               err("failed to attach codec at addr %x\n", addr);
+               pr_err("failed to attach codec at addr %x\n", addr);
                goto err;
        }
 
        ret = wm8750_init(socdev);
        if (ret < 0) {
-       err("failed to initialise WM8750\n");
+               pr_err("failed to initialise WM8750\n");
                goto err;
        }
        return ret;
@@ -961,7 +934,7 @@ static int wm8750_probe(struct platform_device *pdev)
        struct wm8750_priv *wm8750;
        int ret = 0;
 
-       info("WM8750 Audio Codec %s", WM8750_VERSION);
+       pr_info("WM8750 Audio Codec %s", WM8750_VERSION);
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
        if (codec == NULL)
                return -ENOMEM;
@@ -1021,7 +994,7 @@ static int wm8750_remove(struct platform_device *pdev)
        struct snd_soc_codec *codec = socdev->codec;
 
        if (codec->control_data)
-               wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+               wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
        run_delayed_work(&codec->delayed_work);
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
index a97a54a6348ee492c7e2c4b7f0f35b7761ab8db0..8ef30e628b21963a35d10668747f7b76874a4192 100644 (file)
@@ -61,7 +61,7 @@ struct wm8750_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_codec_dai wm8750_dai;
+extern struct snd_soc_dai wm8750_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8750;
 
 #endif
index fb41826c4c4cdba27f39486eab75f888ff08cc99..8604809f0c362b75ee150ae0292663683baebf6f 100644 (file)
 #define AUDIO_NAME "wm8753"
 #define WM8753_VERSION "0.16"
 
-/*
- * Debug
- */
-
-#define WM8753_DEBUG 0
-
-#ifdef WM8753_DEBUG
-#define dbg(format, arg...) \
-       printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) \
-       printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
-#define info(format, arg...) \
-       printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
-#define warn(format, arg...) \
-       printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
-
 static int caps_charge = 2000;
 module_param(caps_charge, int, 0);
 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
@@ -260,28 +241,50 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+static const unsigned int out_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       /* 0000000 - 0101111 = "Analogue mute" */
+       0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0),
+       48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0),
+};
+static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);
 
 static const struct snd_kcontrol_new wm8753_snd_controls[] = {
-SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0),
-
-SOC_DOUBLE_R("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0),
-
-SOC_DOUBLE_R("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, 0, 127, 0),
-SOC_DOUBLE_R("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, 127, 0),
-
-SOC_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0),
-
-SOC_DOUBLE_R("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, 1),
-SOC_DOUBLE_R("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, 7, 1),
-SOC_DOUBLE_R("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, 1),
-
-SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, 1, 0),
-SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, 1, 0),
-
-SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1),
-SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1),
-SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1),
+SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv),
+
+SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0,
+                adc_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V,
+                0, 127, 0, out_tlv),
+SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0,
+                127, 0, out_tlv),
+
+SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv),
+
+SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7,
+                1, mix_tlv),
+SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4,
+                7, 1, mix_tlv),
+SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7,
+                1, voice_mix_tlv),
+
+SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7,
+            1, 0),
+SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7,
+            1, 0),
+
+SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv),
+SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1,
+              mix_tlv),
+SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1,
+              voice_mix_tlv),
 SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
 
 SOC_ENUM("Bass Boost", wm8753_enum[0]),
@@ -291,10 +294,13 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1),
 SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
 SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
 
-SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv),
-SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv),
+SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1,
+              rec_mix_tlv),
+SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1,
+              rec_mix_tlv),
 
-SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0,
+                pga_tlv),
 SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
 SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1),
 
@@ -326,8 +332,8 @@ SOC_ENUM("De-emphasis", wm8753_enum[8]),
 SOC_ENUM("Playback Mono Mix", wm8753_enum[9]),
 SOC_ENUM("Playback Phase", wm8753_enum[10]),
 
-SOC_SINGLE("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0),
-SOC_SINGLE("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0),
+SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv),
+SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv),
 
 SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai),
 
@@ -523,7 +529,7 @@ SND_SOC_DAPM_INPUT("MIC2"),
 SND_SOC_DAPM_VMID("VREF"),
 };
 
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
        /* left mixer */
        {"Left Mixer", "Left Playback Switch", "Left DAC"},
        {"Left Mixer", "Voice Playback Switch", "Voice DAC"},
@@ -674,23 +680,14 @@ static const char *audio_map[][3] = {
 
        /* ACOP */
        {"ACOP", NULL, "ALC Mixer"},
-
-       /* terminator */
-       {NULL, NULL, NULL},
 };
 
 static int wm8753_add_widgets(struct snd_soc_codec *codec)
 {
-       int i;
+       snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
+                                 ARRAY_SIZE(wm8753_dapm_widgets));
 
-       for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
-
-       /* set up the WM8753 audio map */
-       for (i = 0; audio_map[i][0] != NULL; i++) {
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
-       }
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        snd_soc_dapm_new_widgets(codec);
        return 0;
@@ -743,7 +740,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
        pll_div->k = K;
 }
 
-static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai,
                int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
        u16 reg, enable;
@@ -866,7 +863,7 @@ static int get_coeff(int mclk, int rate)
 /*
  * Clock after PLL and dividers
  */
-static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -893,7 +890,7 @@ static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
 /*
  * Set's ADC and Voice DAC format.
  */
-static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -963,7 +960,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
 /*
  * Set's PCM dai fmt and BCLK.
  */
-static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1029,7 +1026,7 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return 0;
 }
 
-static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                int div_id, int div)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1057,7 +1054,7 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
 /*
  * Set's HiFi DAC format.
  */
-static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1090,7 +1087,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
 /*
  * Set's I2S DAI format.
  */
-static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1198,7 +1195,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1213,7 +1210,7 @@ static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return wm8753_pcm_set_dai_fmt(codec_dai, fmt);
 }
 
-static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
@@ -1221,7 +1218,7 @@ static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
 }
 
-static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1236,7 +1233,7 @@ static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
 }
 
-static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -1253,7 +1250,7 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
 }
 
-static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute)
+static int wm8753_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
@@ -1274,29 +1271,29 @@ static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute)
        return 0;
 }
 
-static int wm8753_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm8753_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
 {
        u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e;
 
-       switch (event) {
-       case SNDRV_CTL_POWER_D0: /* full On */
+       switch (level) {
+       case SND_SOC_BIAS_ON:
                /* set vmid to 50k and unmute dac */
                wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
                break;
-       case SNDRV_CTL_POWER_D1: /* partial On */
-       case SNDRV_CTL_POWER_D2: /* partial On */
+       case SND_SOC_BIAS_PREPARE:
                /* set vmid to 5k for quick power up */
                wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
                break;
-       case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+       case SND_SOC_BIAS_STANDBY:
                /* mute dac and set vmid to 500k, enable VREF */
                wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
                break;
-       case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+       case SND_SOC_BIAS_OFF:
                wm8753_write(codec, WM8753_PWR1, 0x0001);
                break;
        }
-       codec->dapm_state = event;
+       codec->bias_level = level;
        return 0;
 }
 
@@ -1319,7 +1316,7 @@ static int wm8753_dapm_event(struct snd_soc_codec *codec, int event)
  * 3. Voice disabled - HIFI over HIFI
  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
  */
-static const struct snd_soc_codec_dai wm8753_all_dai[] = {
+static const struct snd_soc_dai wm8753_all_dai[] = {
 /* DAI HiFi mode 1 */
 {      .name = "WM8753 HiFi",
        .id = 1,
@@ -1459,7 +1456,7 @@ static const struct snd_soc_codec_dai wm8753_all_dai[] = {
 },
 };
 
-struct snd_soc_codec_dai wm8753_dai[2];
+struct snd_soc_dai wm8753_dai[2];
 EXPORT_SYMBOL_GPL(wm8753_dai);
 
 static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
@@ -1500,7 +1497,7 @@ static void wm8753_work(struct work_struct *work)
 {
        struct snd_soc_codec *codec =
                container_of(work, struct snd_soc_codec, delayed_work.work);
-       wm8753_dapm_event(codec, codec->dapm_state);
+       wm8753_set_bias_level(codec, codec->bias_level);
 }
 
 static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
@@ -1512,7 +1509,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
        if (!codec->card)
                return 0;
 
-       wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
@@ -1537,12 +1534,12 @@ static int wm8753_resume(struct platform_device *pdev)
                codec->hw_write(codec->control_data, data, 2);
        }
 
-       wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* charge wm8753 caps */
-       if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
-               wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2);
-               codec->dapm_state = SNDRV_CTL_POWER_D0;
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+               wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+               codec->bias_level = SND_SOC_BIAS_ON;
                schedule_delayed_work(&codec->delayed_work,
                        msecs_to_jiffies(caps_charge));
        }
@@ -1563,10 +1560,10 @@ static int wm8753_init(struct snd_soc_device *socdev)
        codec->owner = THIS_MODULE;
        codec->read = wm8753_read_reg_cache;
        codec->write = wm8753_write;
-       codec->dapm_event = wm8753_dapm_event;
+       codec->set_bias_level = wm8753_set_bias_level;
        codec->dai = wm8753_dai;
        codec->num_dai = 2;
-       codec->reg_cache_size = sizeof(wm8753_reg);
+       codec->reg_cache_size = ARRAY_SIZE(wm8753_reg);
        codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL);
 
        if (codec->reg_cache == NULL)
@@ -1584,8 +1581,8 @@ static int wm8753_init(struct snd_soc_device *socdev)
        }
 
        /* charge output caps */
-       wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2);
-       codec->dapm_state = SNDRV_CTL_POWER_D3hot;
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+       codec->bias_level = SND_SOC_BIAS_STANDBY;
        schedule_delayed_work(&codec->delayed_work,
                msecs_to_jiffies(caps_charge));
 
@@ -1673,13 +1670,13 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 
        ret = i2c_attach_client(i2c);
        if (ret < 0) {
-               err("failed to attach codec at addr %x\n", addr);
+               pr_err("failed to attach codec at addr %x\n", addr);
                goto err;
        }
 
        ret = wm8753_init(socdev);
        if (ret < 0) {
-               err("failed to initialise WM8753\n");
+               pr_err("failed to initialise WM8753\n");
                goto err;
        }
 
@@ -1731,7 +1728,7 @@ static int wm8753_probe(struct platform_device *pdev)
        struct wm8753_priv *wm8753;
        int ret = 0;
 
-       info("WM8753 Audio Codec %s", WM8753_VERSION);
+       pr_info("WM8753 Audio Codec %s", WM8753_VERSION);
 
        setup = socdev->codec_data;
        codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
@@ -1792,7 +1789,7 @@ static int wm8753_remove(struct platform_device *pdev)
        struct snd_soc_codec *codec = socdev->codec;
 
        if (codec->control_data)
-               wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+               wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
        run_delayed_work(&codec->delayed_work);
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
index 95e2a1f53169f6ee9fd5da0e9c1ed14c7af1581f..44f5f1ff0cc7080bfb920c0c5fbb345901896e8a 100644 (file)
@@ -120,7 +120,7 @@ struct wm8753_setup_data {
 #define WM8753_DAI_HIFI                0
 #define WM8753_DAI_VOICE               1
 
-extern struct snd_soc_codec_dai wm8753_dai[2];
+extern struct snd_soc_dai wm8753_dai[2];
 extern struct snd_soc_codec_device soc_codec_dev_wm8753;
 
 #endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
new file mode 100644 (file)
index 0000000..3ecce51
--- /dev/null
@@ -0,0 +1,1626 @@
+/*
+ * wm8990.c  --  WM8990 ALSA Soc Audio driver
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "wm8990.h"
+
+#define AUDIO_NAME "wm8990"
+#define WM8990_VERSION "0.2"
+
+/* codec private data */
+struct wm8990_priv {
+       unsigned int sysclk;
+       unsigned int pcmclk;
+};
+
+/*
+ * wm8990 register cache.  Note that register 0 is not included in the
+ * cache.
+ */
+static const u16 wm8990_reg[] = {
+       0x8990,     /* R0  - Reset */
+       0x0000,     /* R1  - Power Management (1) */
+       0x6000,     /* R2  - Power Management (2) */
+       0x0000,     /* R3  - Power Management (3) */
+       0x4050,     /* R4  - Audio Interface (1) */
+       0x4000,     /* R5  - Audio Interface (2) */
+       0x01C8,     /* R6  - Clocking (1) */
+       0x0000,     /* R7  - Clocking (2) */
+       0x0040,     /* R8  - Audio Interface (3) */
+       0x0040,     /* R9  - Audio Interface (4) */
+       0x0004,     /* R10 - DAC CTRL */
+       0x00C0,     /* R11 - Left DAC Digital Volume */
+       0x00C0,     /* R12 - Right DAC Digital Volume */
+       0x0000,     /* R13 - Digital Side Tone */
+       0x0100,     /* R14 - ADC CTRL */
+       0x00C0,     /* R15 - Left ADC Digital Volume */
+       0x00C0,     /* R16 - Right ADC Digital Volume */
+       0x0000,     /* R17 */
+       0x0000,     /* R18 - GPIO CTRL 1 */
+       0x1000,     /* R19 - GPIO1 & GPIO2 */
+       0x1010,     /* R20 - GPIO3 & GPIO4 */
+       0x1010,     /* R21 - GPIO5 & GPIO6 */
+       0x8000,     /* R22 - GPIOCTRL 2 */
+       0x0800,     /* R23 - GPIO_POL */
+       0x008B,     /* R24 - Left Line Input 1&2 Volume */
+       0x008B,     /* R25 - Left Line Input 3&4 Volume */
+       0x008B,     /* R26 - Right Line Input 1&2 Volume */
+       0x008B,     /* R27 - Right Line Input 3&4 Volume */
+       0x0000,     /* R28 - Left Output Volume */
+       0x0000,     /* R29 - Right Output Volume */
+       0x0066,     /* R30 - Line Outputs Volume */
+       0x0022,     /* R31 - Out3/4 Volume */
+       0x0079,     /* R32 - Left OPGA Volume */
+       0x0079,     /* R33 - Right OPGA Volume */
+       0x0003,     /* R34 - Speaker Volume */
+       0x0003,     /* R35 - ClassD1 */
+       0x0000,     /* R36 */
+       0x0100,     /* R37 - ClassD3 */
+       0x0000,     /* R38 */
+       0x0000,     /* R39 - Input Mixer1 */
+       0x0000,     /* R40 - Input Mixer2 */
+       0x0000,     /* R41 - Input Mixer3 */
+       0x0000,     /* R42 - Input Mixer4 */
+       0x0000,     /* R43 - Input Mixer5 */
+       0x0000,     /* R44 - Input Mixer6 */
+       0x0000,     /* R45 - Output Mixer1 */
+       0x0000,     /* R46 - Output Mixer2 */
+       0x0000,     /* R47 - Output Mixer3 */
+       0x0000,     /* R48 - Output Mixer4 */
+       0x0000,     /* R49 - Output Mixer5 */
+       0x0000,     /* R50 - Output Mixer6 */
+       0x0180,     /* R51 - Out3/4 Mixer */
+       0x0000,     /* R52 - Line Mixer1 */
+       0x0000,     /* R53 - Line Mixer2 */
+       0x0000,     /* R54 - Speaker Mixer */
+       0x0000,     /* R55 - Additional Control */
+       0x0000,     /* R56 - AntiPOP1 */
+       0x0000,     /* R57 - AntiPOP2 */
+       0x0000,     /* R58 - MICBIAS */
+       0x0000,     /* R59 */
+       0x0008,     /* R60 - PLL1 */
+       0x0031,     /* R61 - PLL2 */
+       0x0026,     /* R62 - PLL3 */
+};
+
+/*
+ * read wm8990 register cache
+ */
+static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1);
+       return cache[reg];
+}
+
+/*
+ * write wm8990 register cache
+ */
+static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1);
+
+       /* Reset register is uncached */
+       if (reg == 0)
+               return;
+
+       cache[reg] = value;
+}
+
+/*
+ * write to the wm8990 register space
+ */
+static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg,
+       unsigned int value)
+{
+       u8 data[3];
+
+       data[0] = reg & 0xFF;
+       data[1] = (value >> 8) & 0xFF;
+       data[2] = value & 0xFF;
+
+       wm8990_write_reg_cache(codec, reg, value);
+
+       if (codec->hw_write(codec->control_data, data, 3) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0)
+
+static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+
+static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+
+static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100);
+
+static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+
+static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+
+static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+
+static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+
+static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+
+static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int reg = kcontrol->private_value & 0xff;
+       int ret;
+       u16 val;
+
+       ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       if (ret < 0)
+               return ret;
+
+       /* now hit the volume update bits (always bit 8) */
+       val = wm8990_read_reg_cache(codec, reg);
+       return wm8990_write(codec, reg, val | 0x0100);
+}
+
+#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
+        tlv_array) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+
+static const char *wm8990_digital_sidetone[] =
+       {"None", "Left ADC", "Right ADC", "Reserved"};
+
+static const struct soc_enum wm8990_left_digital_sidetone_enum =
+SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE,
+       WM8990_ADC_TO_DACL_SHIFT,
+       WM8990_ADC_TO_DACL_MASK,
+       wm8990_digital_sidetone);
+
+static const struct soc_enum wm8990_right_digital_sidetone_enum =
+SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE,
+       WM8990_ADC_TO_DACR_SHIFT,
+       WM8990_ADC_TO_DACR_MASK,
+       wm8990_digital_sidetone);
+
+static const char *wm8990_adcmode[] =
+       {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static const struct soc_enum wm8990_right_adcmode_enum =
+SOC_ENUM_SINGLE(WM8990_ADC_CTRL,
+       WM8990_ADC_HPF_CUT_SHIFT,
+       WM8990_ADC_HPF_CUT_MASK,
+       wm8990_adcmode);
+
+static const struct snd_kcontrol_new wm8990_snd_controls[] = {
+/* INMIXL */
+SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0),
+SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0),
+/* INMIXR */
+SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0),
+SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0),
+
+/* LOMIX */
+SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3,
+       WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3,
+       WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3,
+       WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5,
+       WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5,
+       WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5,
+       WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv),
+
+/* ROMIX */
+SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4,
+       WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4,
+       WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4,
+       WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6,
+       WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6,
+       WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6,
+       WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv),
+
+/* LOUT */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME,
+       WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0),
+
+/* ROUT */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME,
+       WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0),
+
+/* LOPGA */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME,
+       WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME,
+       WM8990_LOPGAZC_BIT, 1, 0),
+
+/* ROPGA */
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME,
+       WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME,
+       WM8990_ROPGAZC_BIT, 1, 0),
+
+SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+       WM8990_LONMUTE_BIT, 1, 0),
+SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+       WM8990_LOPMUTE_BIT, 1, 0),
+SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME,
+       WM8990_LOATTN_BIT, 1, 0),
+SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+       WM8990_RONMUTE_BIT, 1, 0),
+SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME,
+       WM8990_ROPMUTE_BIT, 1, 0),
+SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME,
+       WM8990_ROATTN_BIT, 1, 0),
+
+SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME,
+       WM8990_OUT3MUTE_BIT, 1, 0),
+SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME,
+       WM8990_OUT3ATTN_BIT, 1, 0),
+
+SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME,
+       WM8990_OUT4MUTE_BIT, 1, 0),
+SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME,
+       WM8990_OUT4ATTN_BIT, 1, 0),
+
+SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1,
+       WM8990_CDMODE_BIT, 1, 0),
+
+SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME,
+       WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0),
+SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3,
+       WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0),
+SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3,
+       WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+       WM8990_LEFT_DAC_DIGITAL_VOLUME,
+       WM8990_DACL_VOL_SHIFT,
+       WM8990_DACL_VOL_MASK,
+       0,
+       out_dac_tlv),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+       WM8990_RIGHT_DAC_DIGITAL_VOLUME,
+       WM8990_DACR_VOL_SHIFT,
+       WM8990_DACR_VOL_MASK,
+       0,
+       out_dac_tlv),
+
+SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum),
+SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum),
+
+SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE,
+       WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0,
+       out_sidetone_tlv),
+SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE,
+       WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0,
+       out_sidetone_tlv),
+
+SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL,
+       WM8990_ADC_HPF_ENA_BIT, 1, 0),
+
+SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+       WM8990_LEFT_ADC_DIGITAL_VOLUME,
+       WM8990_ADCL_VOL_SHIFT,
+       WM8990_ADCL_VOL_MASK,
+       0,
+       in_adc_tlv),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+       WM8990_RIGHT_ADC_DIGITAL_VOLUME,
+       WM8990_ADCR_VOL_SHIFT,
+       WM8990_ADCR_VOL_MASK,
+       0,
+       in_adc_tlv),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+       WM8990_LEFT_LINE_INPUT_1_2_VOLUME,
+       WM8990_LIN12VOL_SHIFT,
+       WM8990_LIN12VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME,
+       WM8990_LI12ZC_BIT, 1, 0),
+
+SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME,
+       WM8990_LI12MUTE_BIT, 1, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+       WM8990_LEFT_LINE_INPUT_3_4_VOLUME,
+       WM8990_LIN34VOL_SHIFT,
+       WM8990_LIN34VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME,
+       WM8990_LI34ZC_BIT, 1, 0),
+
+SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME,
+       WM8990_LI34MUTE_BIT, 1, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+       WM8990_RIGHT_LINE_INPUT_1_2_VOLUME,
+       WM8990_RIN12VOL_SHIFT,
+       WM8990_RIN12VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME,
+       WM8990_RI12ZC_BIT, 1, 0),
+
+SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME,
+       WM8990_RI12MUTE_BIT, 1, 0),
+
+SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+       WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
+       WM8990_RIN34VOL_SHIFT,
+       WM8990_RIN34VOL_MASK,
+       0,
+       in_pga_tlv),
+
+SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
+       WM8990_RI34ZC_BIT, 1, 0),
+
+SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
+       WM8990_RI34MUTE_BIT, 1, 0),
+
+};
+
+/* add non dapm controls */
+static int wm8990_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                               snd_soc_cnew(&wm8990_snd_controls[i], codec,
+                                       NULL));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/*
+ * _DAPM_ Controls
+ */
+
+static int inmixer_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       u16 reg, fakepower;
+
+       reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2);
+       fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS);
+
+       if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
+               (1 << WM8990_AINLMUX_PWR_BIT))) {
+               reg |= WM8990_AINL_ENA;
+       } else {
+               reg &= ~WM8990_AINL_ENA;
+       }
+
+       if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) |
+               (1 << WM8990_AINRMUX_PWR_BIT))) {
+               reg |= WM8990_AINR_ENA;
+       } else {
+               reg &= ~WM8990_AINL_ENA;
+       }
+       wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
+
+       return 0;
+}
+
+static int outmixer_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       u32 reg_shift = kcontrol->private_value & 0xfff;
+       int ret = 0;
+       u16 reg;
+
+       switch (reg_shift) {
+       case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
+               reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1);
+               if (reg & WM8990_LDLO) {
+                       printk(KERN_WARNING
+                       "Cannot set as Output Mixer 1 LDLO Set\n");
+                       ret = -1;
+               }
+               break;
+       case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
+               reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2);
+               if (reg & WM8990_RDRO) {
+                       printk(KERN_WARNING
+                       "Cannot set as Output Mixer 2 RDRO Set\n");
+                       ret = -1;
+               }
+               break;
+       case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
+               reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER);
+               if (reg & WM8990_LDSPK) {
+                       printk(KERN_WARNING
+                       "Cannot set as Speaker Mixer LDSPK Set\n");
+                       ret = -1;
+               }
+               break;
+       case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
+               reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER);
+               if (reg & WM8990_RDSPK) {
+                       printk(KERN_WARNING
+                       "Cannot set as Speaker Mixer RDSPK Set\n");
+                       ret = -1;
+               }
+               break;
+       }
+
+       return ret;
+}
+
+/* INMIX dB values */
+static const unsigned int in_mix_tlv[] = {
+       TLV_DB_RANGE_HEAD(1),
+       0, 7, TLV_DB_LINEAR_ITEM(-1200, 600),
+};
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0),
+SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0),
+SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0),
+SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0),
+SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3,
+       WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT,
+       7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT,
+       1, 0),
+SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,
+       1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4,
+       WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT,
+       7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT,
+       1, 0),
+SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT,
+       1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8990_ainlmux[] =
+       {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static const struct soc_enum wm8990_ainlmux_enum =
+SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT,
+       ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux);
+
+static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls =
+SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8990_ainrmux[] =
+       {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static const struct soc_enum wm8990_ainrmux_enum =
+SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT,
+       ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux);
+
+static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls =
+SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = {
+SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT,
+                       WM8990_LR4BVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT,
+                       WM8990_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = {
+SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LRBLO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LLBLO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LRI3LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LLI3LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LR12LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LL12LO_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1,
+       WM8990_LDLO_BIT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = {
+SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RLBRO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RRBRO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RLI3RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RRI3RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RL12RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RR12RO_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2,
+       WM8990_RDRO_BIT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = {
+SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1,
+       WM8990_LLOPGALON_BIT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1,
+       WM8990_LROPGALON_BIT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1,
+       WM8990_LOPLON_BIT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = {
+SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1,
+       WM8990_LR12LOP_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1,
+       WM8990_LL12LOP_BIT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1,
+       WM8990_LLOPGALOP_BIT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = {
+SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2,
+       WM8990_RROPGARON_BIT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2,
+       WM8990_RLOPGARON_BIT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2,
+       WM8990_ROPRON_BIT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = {
+SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2,
+       WM8990_RL12ROP_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2,
+       WM8990_RR12ROP_BIT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2,
+       WM8990_RROPGAROP_BIT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = {
+SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER,
+       WM8990_LI4O3_BIT, 1, 0),
+SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER,
+       WM8990_LPGAO3_BIT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = {
+SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER,
+       WM8990_RPGAO4_BIT, 1, 0),
+SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER,
+       WM8990_RI4O4_BIT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = {
+SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER,
+       WM8990_LI2SPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER,
+       WM8990_LB2SPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER,
+       WM8990_LOPGASPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER,
+       WM8990_LDSPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER,
+       WM8990_RDSPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER,
+       WM8990_ROPGASPK_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER,
+       WM8990_RL12ROP_BIT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER,
+       WM8990_RI2SPK_BIT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = {
+/* Input Side */
+/* Input Lines */
+SND_SOC_DAPM_INPUT("LIN1"),
+SND_SOC_DAPM_INPUT("LIN2"),
+SND_SOC_DAPM_INPUT("LIN3"),
+SND_SOC_DAPM_INPUT("LIN4/RXN"),
+SND_SOC_DAPM_INPUT("RIN3"),
+SND_SOC_DAPM_INPUT("RIN4/RXP"),
+SND_SOC_DAPM_INPUT("RIN1"),
+SND_SOC_DAPM_INPUT("RIN2"),
+SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+/* DACs */
+SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2,
+       WM8990_ADCL_ENA_BIT, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2,
+       WM8990_ADCR_ENA_BIT, 0),
+
+/* Input PGAs */
+SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT,
+       0, &wm8990_dapm_lin12_pga_controls[0],
+       ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)),
+SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT,
+       0, &wm8990_dapm_lin34_pga_controls[0],
+       ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT,
+       0, &wm8990_dapm_rin12_pga_controls[0],
+       ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT,
+       0, &wm8990_dapm_rin34_pga_controls[0],
+       ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)),
+
+/* INMIXL */
+SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0,
+       &wm8990_dapm_inmixl_controls[0],
+       ARRAY_SIZE(wm8990_dapm_inmixl_controls),
+       inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* AINLMUX */
+SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0,
+       &wm8990_dapm_ainlmux_controls, inmixer_event,
+       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* INMIXR */
+SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0,
+       &wm8990_dapm_inmixr_controls[0],
+       ARRAY_SIZE(wm8990_dapm_inmixr_controls),
+       inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* AINRMUX */
+SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0,
+       &wm8990_dapm_ainrmux_controls, inmixer_event,
+       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* Output Side */
+/* DACs */
+SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3,
+       WM8990_DACL_ENA_BIT, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3,
+       WM8990_DACR_ENA_BIT, 0),
+
+/* LOMIX */
+SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT,
+       0, &wm8990_dapm_lomix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_lomix_controls),
+       outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LONMIX */
+SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0,
+       &wm8990_dapm_lonmix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_lonmix_controls)),
+
+/* LOPMIX */
+SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0,
+       &wm8990_dapm_lopmix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_lopmix_controls)),
+
+/* OUT3MIX */
+SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0,
+       &wm8990_dapm_out3mix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_out3mix_controls)),
+
+/* SPKMIX */
+SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0,
+       &wm8990_dapm_spkmix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event,
+       SND_SOC_DAPM_PRE_REG),
+
+/* OUT4MIX */
+SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0,
+       &wm8990_dapm_out4mix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_out4mix_controls)),
+
+/* ROPMIX */
+SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0,
+       &wm8990_dapm_ropmix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_ropmix_controls)),
+
+/* RONMIX */
+SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0,
+       &wm8990_dapm_ronmix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_ronmix_controls)),
+
+/* ROMIX */
+SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT,
+       0, &wm8990_dapm_romix_controls[0],
+       ARRAY_SIZE(wm8990_dapm_romix_controls),
+       outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LOUT PGA */
+SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0,
+       NULL, 0),
+
+/* ROUT PGA */
+SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0,
+       NULL, 0),
+
+/* LOPGA */
+SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0,
+       NULL, 0),
+
+/* ROPGA */
+SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0,
+       NULL, 0),
+
+/* MICBIAS */
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1,
+       WM8990_MICBIAS_ENA_BIT, 0),
+
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Make DACs turn on when playing even if not mixed into any outputs */
+       {"Internal DAC Sink", NULL, "Left DAC"},
+       {"Internal DAC Sink", NULL, "Right DAC"},
+
+       /* Make ADCs turn on when recording even if not mixed from any inputs */
+       {"Left ADC", NULL, "Internal ADC Source"},
+       {"Right ADC", NULL, "Internal ADC Source"},
+
+       /* Input Side */
+       /* LIN12 PGA */
+       {"LIN12 PGA", "LIN1 Switch", "LIN1"},
+       {"LIN12 PGA", "LIN2 Switch", "LIN2"},
+       /* LIN34 PGA */
+       {"LIN34 PGA", "LIN3 Switch", "LIN3"},
+       {"LIN34 PGA", "LIN4 Switch", "LIN4"},
+       /* INMIXL */
+       {"INMIXL", "Record Left Volume", "LOMIX"},
+       {"INMIXL", "LIN2 Volume", "LIN2"},
+       {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+       {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+       /* AILNMUX */
+       {"AILNMUX", "INMIXL Mix", "INMIXL"},
+       {"AILNMUX", "DIFFINL Mix", "LIN12PGA"},
+       {"AILNMUX", "DIFFINL Mix", "LIN34PGA"},
+       {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"},
+       {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"},
+       /* ADC */
+       {"Left ADC", NULL, "AILNMUX"},
+
+       /* RIN12 PGA */
+       {"RIN12 PGA", "RIN1 Switch", "RIN1"},
+       {"RIN12 PGA", "RIN2 Switch", "RIN2"},
+       /* RIN34 PGA */
+       {"RIN34 PGA", "RIN3 Switch", "RIN3"},
+       {"RIN34 PGA", "RIN4 Switch", "RIN4"},
+       /* INMIXL */
+       {"INMIXR", "Record Right Volume", "ROMIX"},
+       {"INMIXR", "RIN2 Volume", "RIN2"},
+       {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+       {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+       /* AIRNMUX */
+       {"AIRNMUX", "INMIXR Mix", "INMIXR"},
+       {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"},
+       {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"},
+       {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"},
+       {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"},
+       /* ADC */
+       {"Right ADC", NULL, "AIRNMUX"},
+
+       /* LOMIX */
+       {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+       {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+       {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+       {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+       {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"},
+       {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"},
+       {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+       /* ROMIX */
+       {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+       {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+       {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+       {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+       {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"},
+       {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"},
+       {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+       /* SPKMIX */
+       {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+       {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+       {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"},
+       {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"},
+       {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+       {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+       {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+       {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+
+       /* LONMIX */
+       {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+       {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+       {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+       /* LOPMIX */
+       {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+       {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+       {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+       /* OUT3MIX */
+       {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"},
+       {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+       /* OUT4MIX */
+       {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+       {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"},
+
+       /* RONMIX */
+       {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+       {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+       {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+       /* ROPMIX */
+       {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+       {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+       {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+       /* Out Mixer PGAs */
+       {"LOPGA", NULL, "LOMIX"},
+       {"ROPGA", NULL, "ROMIX"},
+
+       {"LOUT PGA", NULL, "LOMIX"},
+       {"ROUT PGA", NULL, "ROMIX"},
+
+       /* Output Pins */
+       {"LON", NULL, "LONMIX"},
+       {"LOP", NULL, "LOPMIX"},
+       {"OUT", NULL, "OUT3MIX"},
+       {"LOUT", NULL, "LOUT PGA"},
+       {"SPKN", NULL, "SPKMIX"},
+       {"ROUT", NULL, "ROUT PGA"},
+       {"OUT4", NULL, "OUT4MIX"},
+       {"ROP", NULL, "ROPMIX"},
+       {"RON", NULL, "RONMIX"},
+};
+
+static int wm8990_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets,
+                                 ARRAY_SIZE(wm8990_dapm_widgets));
+
+       /* set up the WM8990 audio map */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+/* PLL divisors */
+struct _pll_div {
+       u32 div2;
+       u32 n;
+       u32 k;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 16) * 10)
+
+static void pll_factors(struct _pll_div *pll_div, unsigned int target,
+       unsigned int source)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod;
+
+
+       Ndiv = target / source;
+       if (Ndiv < 6) {
+               source >>= 1;
+               pll_div->div2 = 1;
+               Ndiv = target / source;
+       } else
+               pll_div->div2 = 0;
+
+       if ((Ndiv < 6) || (Ndiv > 12))
+               printk(KERN_WARNING
+               "WM8990 N value outwith recommended range! N = %d\n", Ndiv);
+
+       pll_div->n = Ndiv;
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       /* Check if we need to round */
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       K /= 10;
+
+       pll_div->k = K;
+}
+
+static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai,
+               int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       u16 reg;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct _pll_div pll_div;
+
+       if (freq_in && freq_out) {
+               pll_factors(&pll_div, freq_out * 4, freq_in);
+
+               /* Turn on PLL */
+               reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2);
+               reg |= WM8990_PLL_ENA;
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
+
+               /* sysclk comes from PLL */
+               reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2);
+               wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
+
+               /* set up N , fractional mode and pre-divisor if neccessary */
+               wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
+                       (pll_div.div2?WM8990_PRESCALE:0));
+               wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
+               wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
+       } else {
+               /* Turn on PLL */
+               reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2);
+               reg &= ~WM8990_PLL_ENA;
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
+       }
+       return 0;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8990_priv *wm8990 = codec->private_data;
+
+       wm8990->sysclk = freq;
+       return 0;
+}
+
+/*
+ * Set's ADC and Voice DAC format.
+ */
+static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 audio1, audio3;
+
+       audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
+       audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               audio3 &= ~WM8990_AIF_MSTR1;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               audio3 |= WM8990_AIF_MSTR1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       audio1 &= ~WM8990_AIF_FMT_MASK;
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               audio1 |= WM8990_AIF_TMF_I2S;
+               audio1 &= ~WM8990_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               audio1 |= WM8990_AIF_TMF_RIGHTJ;
+               audio1 &= ~WM8990_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               audio1 |= WM8990_AIF_TMF_LEFTJ;
+               audio1 &= ~WM8990_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               audio1 |= WM8990_AIF_TMF_DSP;
+               audio1 &= ~WM8990_AIF_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
+       wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
+       return 0;
+}
+
+static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+               int div_id, int div)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 reg;
+
+       switch (div_id) {
+       case WM8990_MCLK_DIV:
+               reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) &
+                       ~WM8990_MCLK_DIV_MASK;
+               wm8990_write(codec, WM8990_CLOCKING_2, reg | div);
+               break;
+       case WM8990_DACCLK_DIV:
+               reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) &
+                       ~WM8990_DAC_CLKDIV_MASK;
+               wm8990_write(codec, WM8990_CLOCKING_2, reg | div);
+               break;
+       case WM8990_ADCCLK_DIV:
+               reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) &
+                       ~WM8990_ADC_CLKDIV_MASK;
+               wm8990_write(codec, WM8990_CLOCKING_2, reg | div);
+               break;
+       case WM8990_BCLK_DIV:
+               reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) &
+                       ~WM8990_BCLK_DIV_MASK;
+               wm8990_write(codec, WM8990_CLOCKING_1, reg | div);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8990_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
+
+       audio1 &= ~WM8990_AIF_WL_MASK;
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               audio1 |= WM8990_AIF_WL_20BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               audio1 |= WM8990_AIF_WL_24BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               audio1 |= WM8990_AIF_WL_32BITS;
+               break;
+       }
+
+       wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
+       return 0;
+}
+
+static int wm8990_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 val;
+
+       val  = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
+
+       if (mute)
+               wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+       else
+               wm8990_write(codec, WM8990_DAC_CTRL, val);
+
+       return 0;
+}
+
+static int wm8990_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       u16 val;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Enable all output discharge bits */
+                       wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+                               WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
+                               WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
+                               WM8990_DIS_ROUT);
+
+                       /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+                       wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+                                    WM8990_BUFDCOPEN | WM8990_POBCTRL |
+                                    WM8990_VMIDTOG);
+
+                       /* Delay to allow output caps to discharge */
+                       msleep(msecs_to_jiffies(300));
+
+                       /* Disable VMIDTOG */
+                       wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+                                    WM8990_BUFDCOPEN | WM8990_POBCTRL);
+
+                       /* disable all output discharge bits */
+                       wm8990_write(codec, WM8990_ANTIPOP1, 0);
+
+                       /* Enable outputs */
+                       wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
+
+                       msleep(msecs_to_jiffies(50));
+
+                       /* Enable VMID at 2x50k */
+                       wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02);
+
+                       msleep(msecs_to_jiffies(100));
+
+                       /* Enable VREF */
+                       wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+
+                       msleep(msecs_to_jiffies(600));
+
+                       /* Enable BUFIOEN */
+                       wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+                                    WM8990_BUFDCOPEN | WM8990_POBCTRL |
+                                    WM8990_BUFIOEN);
+
+                       /* Disable outputs */
+                       wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3);
+
+                       /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+                       wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
+               } else {
+                       /* ON -> standby */
+
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               /* Enable POBCTRL and SOFT_ST */
+               wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+                       WM8990_POBCTRL | WM8990_BUFIOEN);
+
+               /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+               wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
+                       WM8990_BUFDCOPEN | WM8990_POBCTRL |
+                       WM8990_BUFIOEN);
+
+               /* mute DAC */
+               val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL);
+               wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
+
+               /* Enable any disabled outputs */
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
+
+               /* Disable VMID */
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
+
+               msleep(msecs_to_jiffies(300));
+
+               /* Enable all output discharge bits */
+               wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
+                       WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
+                       WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
+                       WM8990_DIS_ROUT);
+
+               /* Disable VREF */
+               wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0);
+
+               /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+               wm8990_write(codec, WM8990_ANTIPOP2, 0x0);
+               break;
+       }
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000)
+
+#define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+/*
+ * The WM8990 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+struct snd_soc_dai wm8990_dai = {
+/* ADC/DAC on primary */
+       .name = "WM8990 ADC/DAC Primary",
+       .id = 1,
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8990_RATES,
+               .formats = WM8990_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8990_RATES,
+               .formats = WM8990_FORMATS,},
+       .ops = {
+               .hw_params = wm8990_hw_params,},
+       .dai_ops = {
+               .digital_mute = wm8990_mute,
+               .set_fmt = wm8990_set_dai_fmt,
+               .set_clkdiv = wm8990_set_dai_clkdiv,
+               .set_pll = wm8990_set_dai_pll,
+               .set_sysclk = wm8990_set_dai_sysclk,
+       },
+};
+EXPORT_SYMBOL_GPL(wm8990_dai);
+
+static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       /* we only need to suspend if we are a valid card */
+       if (!codec->card)
+               return 0;
+
+       wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8990_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u8 data[2];
+       u16 *cache = codec->reg_cache;
+
+       /* we only need to resume if we are a valid card */
+       if (!codec->card)
+               return 0;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) {
+               if (i + 1 == WM8990_RESET)
+                       continue;
+               data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
+               data[1] = cache[i] & 0x00ff;
+               codec->hw_write(codec->control_data, data, 2);
+       }
+
+       wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+
+/*
+ * initialise the WM8990 driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int wm8990_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       u16 reg;
+       int ret = 0;
+
+       codec->name = "WM8990";
+       codec->owner = THIS_MODULE;
+       codec->read = wm8990_read_reg_cache;
+       codec->write = wm8990_write;
+       codec->set_bias_level = wm8990_set_bias_level;
+       codec->dai = &wm8990_dai;
+       codec->num_dai = 2;
+       codec->reg_cache_size = ARRAY_SIZE(wm8990_reg);
+       codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL);
+
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       wm8990_reset(codec);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8990: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* charge output caps */
+       codec->bias_level = SND_SOC_BIAS_OFF;
+       wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4);
+       wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1);
+
+       reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) &
+               ~WM8990_GPIO1_SEL_MASK;
+       wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1);
+
+       reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2);
+       wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
+
+       wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+       wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+
+       wm8990_add_controls(codec);
+       wm8990_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "wm8990: failed to register card\n");
+               goto card_err;
+       }
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+/* If the i2c layer weren't so broken, we could pass this kind of data
+   around */
+static struct snd_soc_device *wm8990_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+/*
+ * WM891 2 wire address is determined by GPIO5
+ * state during powerup.
+ *    low  = 0x34
+ *    high = 0x36
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver wm8990_i2c_driver;
+static struct i2c_client client_template;
+
+static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = wm8990_socdev;
+       struct wm8990_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               pr_err("failed to attach codec at addr %x\n", addr);
+               goto err;
+       }
+
+       ret = wm8990_init(socdev);
+       if (ret < 0) {
+               pr_err("failed to initialise WM8990\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int wm8990_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int wm8990_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, wm8990_codec_probe);
+}
+
+static struct i2c_driver wm8990_i2c_driver = {
+       .driver = {
+               .name = "WM8990 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .attach_adapter = wm8990_i2c_attach,
+       .detach_client =  wm8990_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "WM8990",
+       .driver = &wm8990_i2c_driver,
+};
+#endif
+
+static int wm8990_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct wm8990_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct wm8990_priv *wm8990;
+       int ret = 0;
+
+       pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
+       if (wm8990 == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = wm8990;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+       wm8990_socdev = socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               ret = i2c_add_driver(&wm8990_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+               /* Add other interfaces here */
+#endif
+       return ret;
+}
+
+/* power down chip */
+static int wm8990_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       if (codec->control_data)
+               wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8990_i2c_driver);
+#endif
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8990 = {
+       .probe =        wm8990_probe,
+       .remove =       wm8990_remove,
+       .suspend =      wm8990_suspend,
+       .resume =       wm8990_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
+
+MODULE_DESCRIPTION("ASoC WM8990 driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
new file mode 100644 (file)
index 0000000..6bea574
--- /dev/null
@@ -0,0 +1,832 @@
+/*
+ * wm8990.h  --  audio driver for WM8990
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __WM8990REGISTERDEFS_H__
+#define __WM8990REGISTERDEFS_H__
+
+/*
+ * Register values.
+ */
+#define WM8990_RESET                            0x00
+#define WM8990_POWER_MANAGEMENT_1               0x01
+#define WM8990_POWER_MANAGEMENT_2               0x02
+#define WM8990_POWER_MANAGEMENT_3               0x03
+#define WM8990_AUDIO_INTERFACE_1                0x04
+#define WM8990_AUDIO_INTERFACE_2                0x05
+#define WM8990_CLOCKING_1                       0x06
+#define WM8990_CLOCKING_2                       0x07
+#define WM8990_AUDIO_INTERFACE_3                0x08
+#define WM8990_AUDIO_INTERFACE_4                0x09
+#define WM8990_DAC_CTRL                         0x0A
+#define WM8990_LEFT_DAC_DIGITAL_VOLUME          0x0B
+#define WM8990_RIGHT_DAC_DIGITAL_VOLUME         0x0C
+#define WM8990_DIGITAL_SIDE_TONE                0x0D
+#define WM8990_ADC_CTRL                         0x0E
+#define WM8990_LEFT_ADC_DIGITAL_VOLUME          0x0F
+#define WM8990_RIGHT_ADC_DIGITAL_VOLUME         0x10
+#define WM8990_GPIO_CTRL_1                      0x12
+#define WM8990_GPIO1_GPIO2                      0x13
+#define WM8990_GPIO3_GPIO4                      0x14
+#define WM8990_GPIO5_GPIO6                      0x15
+#define WM8990_GPIOCTRL_2                       0x16
+#define WM8990_GPIO_POL                         0x17
+#define WM8990_LEFT_LINE_INPUT_1_2_VOLUME       0x18
+#define WM8990_LEFT_LINE_INPUT_3_4_VOLUME       0x19
+#define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME      0x1A
+#define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME      0x1B
+#define WM8990_LEFT_OUTPUT_VOLUME               0x1C
+#define WM8990_RIGHT_OUTPUT_VOLUME              0x1D
+#define WM8990_LINE_OUTPUTS_VOLUME              0x1E
+#define WM8990_OUT3_4_VOLUME                    0x1F
+#define WM8990_LEFT_OPGA_VOLUME                 0x20
+#define WM8990_RIGHT_OPGA_VOLUME                0x21
+#define WM8990_SPEAKER_VOLUME                   0x22
+#define WM8990_CLASSD1                          0x23
+#define WM8990_CLASSD3                          0x25
+#define WM8990_INPUT_MIXER1                     0x27
+#define WM8990_INPUT_MIXER2                     0x28
+#define WM8990_INPUT_MIXER3                     0x29
+#define WM8990_INPUT_MIXER4                     0x2A
+#define WM8990_INPUT_MIXER5                     0x2B
+#define WM8990_INPUT_MIXER6                     0x2C
+#define WM8990_OUTPUT_MIXER1                    0x2D
+#define WM8990_OUTPUT_MIXER2                    0x2E
+#define WM8990_OUTPUT_MIXER3                    0x2F
+#define WM8990_OUTPUT_MIXER4                    0x30
+#define WM8990_OUTPUT_MIXER5                    0x31
+#define WM8990_OUTPUT_MIXER6                    0x32
+#define WM8990_OUT3_4_MIXER                     0x33
+#define WM8990_LINE_MIXER1                      0x34
+#define WM8990_LINE_MIXER2                      0x35
+#define WM8990_SPEAKER_MIXER                    0x36
+#define WM8990_ADDITIONAL_CONTROL               0x37
+#define WM8990_ANTIPOP1                         0x38
+#define WM8990_ANTIPOP2                         0x39
+#define WM8990_MICBIAS                          0x3A
+#define WM8990_PLL1                             0x3C
+#define WM8990_PLL2                             0x3D
+#define WM8990_PLL3                             0x3E
+#define WM8990_INTDRIVBITS                     0x3F
+
+#define WM8990_REGISTER_COUNT                   60
+#define WM8990_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset
+ */
+#define WM8990_SW_RESET_CHIP_ID_MASK            0xFFFF  /* SW_RESET_CHIP_ID */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8990_SPK_ENA                          0x1000  /* SPK_ENA */
+#define WM8990_SPK_ENA_BIT                     12
+#define WM8990_OUT3_ENA                         0x0800  /* OUT3_ENA */
+#define WM8990_OUT3_ENA_BIT                    11
+#define WM8990_OUT4_ENA                         0x0400  /* OUT4_ENA */
+#define WM8990_OUT4_ENA_BIT                    10
+#define WM8990_LOUT_ENA                         0x0200  /* LOUT_ENA */
+#define WM8990_LOUT_ENA_BIT                    9
+#define WM8990_ROUT_ENA                         0x0100  /* ROUT_ENA */
+#define WM8990_ROUT_ENA_BIT                    8
+#define WM8990_MICBIAS_ENA                      0x0010  /* MICBIAS_ENA */
+#define WM8990_MICBIAS_ENA_BIT                 4
+#define WM8990_VMID_MODE_MASK                   0x0006  /* VMID_MODE - [2:1] */
+#define WM8990_VREF_ENA                         0x0001  /* VREF_ENA */
+#define WM8990_VREF_ENA_BIT                    0
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8990_PLL_ENA                          0x8000  /* PLL_ENA */
+#define WM8990_PLL_ENA_BIT                     15
+#define WM8990_TSHUT_ENA                        0x4000  /* TSHUT_ENA */
+#define WM8990_TSHUT_ENA_BIT                   14
+#define WM8990_TSHUT_OPDIS                      0x2000  /* TSHUT_OPDIS */
+#define WM8990_TSHUT_OPDIS_BIT                 13
+#define WM8990_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8990_OPCLK_ENA_BIT                   11
+#define WM8990_AINL_ENA                         0x0200  /* AINL_ENA */
+#define WM8990_AINL_ENA_BIT                    9
+#define WM8990_AINR_ENA                         0x0100  /* AINR_ENA */
+#define WM8990_AINR_ENA_BIT                    8
+#define WM8990_LIN34_ENA                        0x0080  /* LIN34_ENA */
+#define WM8990_LIN34_ENA_BIT                   7
+#define WM8990_LIN12_ENA                        0x0040  /* LIN12_ENA */
+#define WM8990_LIN12_ENA_BIT                   6
+#define WM8990_RIN34_ENA                        0x0020  /* RIN34_ENA */
+#define WM8990_RIN34_ENA_BIT                   5
+#define WM8990_RIN12_ENA                        0x0010  /* RIN12_ENA */
+#define WM8990_RIN12_ENA_BIT                   4
+#define WM8990_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8990_ADCL_ENA_BIT                    1
+#define WM8990_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8990_ADCR_ENA_BIT                    0
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8990_LON_ENA                          0x2000  /* LON_ENA */
+#define WM8990_LON_ENA_BIT                     13
+#define WM8990_LOP_ENA                          0x1000  /* LOP_ENA */
+#define WM8990_LOP_ENA_BIT                     12
+#define WM8990_RON_ENA                          0x0800  /* RON_ENA */
+#define WM8990_RON_ENA_BIT                     11
+#define WM8990_ROP_ENA                          0x0400  /* ROP_ENA */
+#define WM8990_ROP_ENA_BIT                     10
+#define WM8990_LOPGA_ENA                        0x0080  /* LOPGA_ENA */
+#define WM8990_LOPGA_ENA_BIT                   7
+#define WM8990_ROPGA_ENA                        0x0040  /* ROPGA_ENA */
+#define WM8990_ROPGA_ENA_BIT                   6
+#define WM8990_LOMIX_ENA                        0x0020  /* LOMIX_ENA */
+#define WM8990_LOMIX_ENA_BIT                   5
+#define WM8990_ROMIX_ENA                        0x0010  /* ROMIX_ENA */
+#define WM8990_ROMIX_ENA_BIT                   4
+#define WM8990_DACL_ENA                         0x0002  /* DACL_ENA */
+#define WM8990_DACL_ENA_BIT                    1
+#define WM8990_DACR_ENA                         0x0001  /* DACR_ENA */
+#define WM8990_DACR_ENA_BIT                    0
+
+/*
+ * R4 (0x04) - Audio Interface (1)
+ */
+#define WM8990_AIFADCL_SRC                      0x8000  /* AIFADCL_SRC */
+#define WM8990_AIFADCR_SRC                      0x4000  /* AIFADCR_SRC */
+#define WM8990_AIFADC_TDM                       0x2000  /* AIFADC_TDM */
+#define WM8990_AIFADC_TDM_CHAN                  0x1000  /* AIFADC_TDM_CHAN */
+#define WM8990_AIF_BCLK_INV                     0x0100  /* AIF_BCLK_INV */
+#define WM8990_AIF_LRCLK_INV                    0x0080  /* AIF_LRCLK_INV */
+#define WM8990_AIF_WL_MASK                      0x0060  /* AIF_WL - [6:5] */
+#define WM8990_AIF_WL_16BITS                   (0 << 5)
+#define WM8990_AIF_WL_20BITS                   (1 << 5)
+#define WM8990_AIF_WL_24BITS                   (2 << 5)
+#define WM8990_AIF_WL_32BITS                   (3 << 5)
+#define WM8990_AIF_FMT_MASK                     0x0018  /* AIF_FMT - [4:3] */
+#define WM8990_AIF_TMF_RIGHTJ                  (0 << 3)
+#define WM8990_AIF_TMF_LEFTJ                   (1 << 3)
+#define WM8990_AIF_TMF_I2S                     (2 << 3)
+#define WM8990_AIF_TMF_DSP                     (3 << 3)
+
+/*
+ * R5 (0x05) - Audio Interface (2)
+ */
+#define WM8990_DACL_SRC                         0x8000  /* DACL_SRC */
+#define WM8990_DACR_SRC                         0x4000  /* DACR_SRC */
+#define WM8990_AIFDAC_TDM                       0x2000  /* AIFDAC_TDM */
+#define WM8990_AIFDAC_TDM_CHAN                  0x1000  /* AIFDAC_TDM_CHAN */
+#define WM8990_DAC_BOOST_MASK                   0x0C00  /* DAC_BOOST */
+#define WM8990_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8990_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8990_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8990_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8990_LOOPBACK                         0x0001  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clocking (1)
+ */
+#define WM8990_TOCLK_RATE                       0x8000  /* TOCLK_RATE */
+#define WM8990_TOCLK_ENA                        0x4000  /* TOCLK_ENA */
+#define WM8990_OPCLKDIV_MASK                    0x1E00  /* OPCLKDIV - [12:9] */
+#define WM8990_DCLKDIV_MASK                     0x01C0  /* DCLKDIV - [8:6] */
+#define WM8990_BCLK_DIV_MASK                    0x001E  /* BCLK_DIV - [4:1] */
+#define WM8990_BCLK_DIV_1                      (0x0 << 1)
+#define WM8990_BCLK_DIV_1_5                    (0x1 << 1)
+#define WM8990_BCLK_DIV_2                      (0x2 << 1)
+#define WM8990_BCLK_DIV_3                      (0x3 << 1)
+#define WM8990_BCLK_DIV_4                      (0x4 << 1)
+#define WM8990_BCLK_DIV_5_5                    (0x5 << 1)
+#define WM8990_BCLK_DIV_6                      (0x6 << 1)
+#define WM8990_BCLK_DIV_8                      (0x7 << 1)
+#define WM8990_BCLK_DIV_11                     (0x8 << 1)
+#define WM8990_BCLK_DIV_12                     (0x9 << 1)
+#define WM8990_BCLK_DIV_16                     (0xA << 1)
+#define WM8990_BCLK_DIV_22                     (0xB << 1)
+#define WM8990_BCLK_DIV_24                     (0xC << 1)
+#define WM8990_BCLK_DIV_32                     (0xD << 1)
+#define WM8990_BCLK_DIV_44                     (0xE << 1)
+#define WM8990_BCLK_DIV_48                     (0xF << 1)
+
+/*
+ * R7 (0x07) - Clocking (2)
+ */
+#define WM8990_MCLK_SRC                         0x8000  /* MCLK_SRC */
+#define WM8990_SYSCLK_SRC                       0x4000  /* SYSCLK_SRC */
+#define WM8990_CLK_FORCE                        0x2000  /* CLK_FORCE */
+#define WM8990_MCLK_DIV_MASK                    0x1800  /* MCLK_DIV - [12:11] */
+#define WM8990_MCLK_DIV_1                      (0 << 11)
+#define WM8990_MCLK_DIV_2                      (2 << 11)
+#define WM8990_MCLK_INV                         0x0400  /* MCLK_INV */
+#define WM8990_ADC_CLKDIV_MASK                  0x00E0  /* ADC_CLKDIV */
+#define WM8990_ADC_CLKDIV_1                    (0 << 5)
+#define WM8990_ADC_CLKDIV_1_5                  (1 << 5)
+#define WM8990_ADC_CLKDIV_2                    (2 << 5)
+#define WM8990_ADC_CLKDIV_3                    (3 << 5)
+#define WM8990_ADC_CLKDIV_4                    (4 << 5)
+#define WM8990_ADC_CLKDIV_5_5                  (5 << 5)
+#define WM8990_ADC_CLKDIV_6                    (6 << 5)
+#define WM8990_DAC_CLKDIV_MASK                  0x001C  /* DAC_CLKDIV - [4:2] */
+#define WM8990_DAC_CLKDIV_1                    (0 << 2)
+#define WM8990_DAC_CLKDIV_1_5                  (1 << 2)
+#define WM8990_DAC_CLKDIV_2                    (2 << 2)
+#define WM8990_DAC_CLKDIV_3                    (3 << 2)
+#define WM8990_DAC_CLKDIV_4                    (4 << 2)
+#define WM8990_DAC_CLKDIV_5_5                  (5 << 2)
+#define WM8990_DAC_CLKDIV_6                    (6 << 2)
+
+/*
+ * R8 (0x08) - Audio Interface (3)
+ */
+#define WM8990_AIF_MSTR1                        0x8000  /* AIF_MSTR1 */
+#define WM8990_AIF_MSTR2                        0x4000  /* AIF_MSTR2 */
+#define WM8990_AIF_SEL                          0x2000  /* AIF_SEL */
+#define WM8990_ADCLRC_DIR                       0x0800  /* ADCLRC_DIR */
+#define WM8990_ADCLRC_RATE_MASK                 0x07FF  /* ADCLRC_RATE */
+
+/*
+ * R9 (0x09) - Audio Interface (4)
+ */
+#define WM8990_ALRCGPIO1                        0x8000  /* ALRCGPIO1 */
+#define WM8990_ALRCBGPIO6                       0x4000  /* ALRCBGPIO6 */
+#define WM8990_AIF_TRIS                         0x2000  /* AIF_TRIS */
+#define WM8990_DACLRC_DIR                       0x0800  /* DACLRC_DIR */
+#define WM8990_DACLRC_RATE_MASK                 0x07FF  /* DACLRC_RATE */
+
+/*
+ * R10 (0x0A) - DAC CTRL
+ */
+#define WM8990_AIF_LRCLKRATE                    0x0400  /* AIF_LRCLKRATE */
+#define WM8990_DAC_MONO                         0x0200  /* DAC_MONO */
+#define WM8990_DAC_SB_FILT                      0x0100  /* DAC_SB_FILT */
+#define WM8990_DAC_MUTERATE                     0x0080  /* DAC_MUTERATE */
+#define WM8990_DAC_MUTEMODE                     0x0040  /* DAC_MUTEMODE */
+#define WM8990_DEEMP_MASK                       0x0030  /* DEEMP - [5:4] */
+#define WM8990_DAC_MUTE                         0x0004  /* DAC_MUTE */
+#define WM8990_DACL_DATINV                      0x0002  /* DACL_DATINV */
+#define WM8990_DACR_DATINV                      0x0001  /* DACR_DATINV */
+
+/*
+ * R11 (0x0B) - Left DAC Digital Volume
+ */
+#define WM8990_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8990_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8990_DACL_VOL_SHIFT                  0
+/*
+ * R12 (0x0C) - Right DAC Digital Volume
+ */
+#define WM8990_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8990_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8990_DACR_VOL_SHIFT                  0
+/*
+ * R13 (0x0D) - Digital Side Tone
+ */
+#define WM8990_ADCL_DAC_SVOL_MASK               0x0F  /* ADCL_DAC_SVOL */
+#define WM8990_ADCL_DAC_SVOL_SHIFT             9
+#define WM8990_ADCR_DAC_SVOL_MASK               0x0F  /* ADCR_DAC_SVOL */
+#define WM8990_ADCR_DAC_SVOL_SHIFT             5
+#define WM8990_ADC_TO_DACL_MASK                 0x03  /* ADC_TO_DACL - [3:2] */
+#define WM8990_ADC_TO_DACL_SHIFT               2
+#define WM8990_ADC_TO_DACR_MASK                 0x03  /* ADC_TO_DACR - [1:0] */
+#define WM8990_ADC_TO_DACR_SHIFT               0
+
+/*
+ * R14 (0x0E) - ADC CTRL
+ */
+#define WM8990_ADC_HPF_ENA                      0x0100  /* ADC_HPF_ENA */
+#define WM8990_ADC_HPF_ENA_BIT                 8
+#define WM8990_ADC_HPF_CUT_MASK                 0x03  /* ADC_HPF_CUT - [6:5] */
+#define WM8990_ADC_HPF_CUT_SHIFT               5
+#define WM8990_ADCL_DATINV                      0x0002  /* ADCL_DATINV */
+#define WM8990_ADCL_DATINV_BIT                 1
+#define WM8990_ADCR_DATINV                      0x0001  /* ADCR_DATINV */
+#define WM8990_ADCR_DATINV_BIT                 0
+
+/*
+ * R15 (0x0F) - Left ADC Digital Volume
+ */
+#define WM8990_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8990_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8990_ADCL_VOL_SHIFT                  0
+
+/*
+ * R16 (0x10) - Right ADC Digital Volume
+ */
+#define WM8990_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8990_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8990_ADCR_VOL_SHIFT                  0
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8990_IRQ                              0x1000  /* IRQ */
+#define WM8990_TEMPOK                           0x0800  /* TEMPOK */
+#define WM8990_MICSHRT                          0x0400  /* MICSHRT */
+#define WM8990_MICDET                           0x0200  /* MICDET */
+#define WM8990_PLL_LCK                          0x0100  /* PLL_LCK */
+#define WM8990_GPI8_STATUS                      0x0080  /* GPI8_STATUS */
+#define WM8990_GPI7_STATUS                      0x0040  /* GPI7_STATUS */
+#define WM8990_GPIO6_STATUS                     0x0020  /* GPIO6_STATUS */
+#define WM8990_GPIO5_STATUS                     0x0010  /* GPIO5_STATUS */
+#define WM8990_GPIO4_STATUS                     0x0008  /* GPIO4_STATUS */
+#define WM8990_GPIO3_STATUS                     0x0004  /* GPIO3_STATUS */
+#define WM8990_GPIO2_STATUS                     0x0002  /* GPIO2_STATUS */
+#define WM8990_GPIO1_STATUS                     0x0001  /* GPIO1_STATUS */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8990_GPIO2_DEB_ENA                    0x8000  /* GPIO2_DEB_ENA */
+#define WM8990_GPIO2_IRQ_ENA                    0x4000  /* GPIO2_IRQ_ENA */
+#define WM8990_GPIO2_PU                         0x2000  /* GPIO2_PU */
+#define WM8990_GPIO2_PD                         0x1000  /* GPIO2_PD */
+#define WM8990_GPIO2_SEL_MASK                   0x0F00  /* GPIO2_SEL - [11:8] */
+#define WM8990_GPIO1_DEB_ENA                    0x0080  /* GPIO1_DEB_ENA */
+#define WM8990_GPIO1_IRQ_ENA                    0x0040  /* GPIO1_IRQ_ENA */
+#define WM8990_GPIO1_PU                         0x0020  /* GPIO1_PU */
+#define WM8990_GPIO1_PD                         0x0010  /* GPIO1_PD */
+#define WM8990_GPIO1_SEL_MASK                   0x000F  /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8990_GPIO4_DEB_ENA                    0x8000  /* GPIO4_DEB_ENA */
+#define WM8990_GPIO4_IRQ_ENA                    0x4000  /* GPIO4_IRQ_ENA */
+#define WM8990_GPIO4_PU                         0x2000  /* GPIO4_PU */
+#define WM8990_GPIO4_PD                         0x1000  /* GPIO4_PD */
+#define WM8990_GPIO4_SEL_MASK                   0x0F00  /* GPIO4_SEL - [11:8] */
+#define WM8990_GPIO3_DEB_ENA                    0x0080  /* GPIO3_DEB_ENA */
+#define WM8990_GPIO3_IRQ_ENA                    0x0040  /* GPIO3_IRQ_ENA */
+#define WM8990_GPIO3_PU                         0x0020  /* GPIO3_PU */
+#define WM8990_GPIO3_PD                         0x0010  /* GPIO3_PD */
+#define WM8990_GPIO3_SEL_MASK                   0x000F  /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8990_GPIO6_DEB_ENA                    0x8000  /* GPIO6_DEB_ENA */
+#define WM8990_GPIO6_IRQ_ENA                    0x4000  /* GPIO6_IRQ_ENA */
+#define WM8990_GPIO6_PU                         0x2000  /* GPIO6_PU */
+#define WM8990_GPIO6_PD                         0x1000  /* GPIO6_PD */
+#define WM8990_GPIO6_SEL_MASK                   0x0F00  /* GPIO6_SEL - [11:8] */
+#define WM8990_GPIO5_DEB_ENA                    0x0080  /* GPIO5_DEB_ENA */
+#define WM8990_GPIO5_IRQ_ENA                    0x0040  /* GPIO5_IRQ_ENA */
+#define WM8990_GPIO5_PU                         0x0020  /* GPIO5_PU */
+#define WM8990_GPIO5_PD                         0x0010  /* GPIO5_PD */
+#define WM8990_GPIO5_SEL_MASK                   0x000F  /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8990_RD_3W_ENA                        0x8000  /* RD_3W_ENA */
+#define WM8990_MODE_3W4W                        0x4000  /* MODE_3W4W */
+#define WM8990_TEMPOK_IRQ_ENA                   0x0800  /* TEMPOK_IRQ_ENA */
+#define WM8990_MICSHRT_IRQ_ENA                  0x0400  /* MICSHRT_IRQ_ENA */
+#define WM8990_MICDET_IRQ_ENA                   0x0200  /* MICDET_IRQ_ENA */
+#define WM8990_PLL_LCK_IRQ_ENA                  0x0100  /* PLL_LCK_IRQ_ENA */
+#define WM8990_GPI8_DEB_ENA                     0x0080  /* GPI8_DEB_ENA */
+#define WM8990_GPI8_IRQ_ENA                     0x0040  /* GPI8_IRQ_ENA */
+#define WM8990_GPI8_ENA                         0x0010  /* GPI8_ENA */
+#define WM8990_GPI7_DEB_ENA                     0x0008  /* GPI7_DEB_ENA */
+#define WM8990_GPI7_IRQ_ENA                     0x0004  /* GPI7_IRQ_ENA */
+#define WM8990_GPI7_ENA                         0x0001  /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8990_IRQ_INV                          0x1000  /* IRQ_INV */
+#define WM8990_TEMPOK_POL                       0x0800  /* TEMPOK_POL */
+#define WM8990_MICSHRT_POL                      0x0400  /* MICSHRT_POL */
+#define WM8990_MICDET_POL                       0x0200  /* MICDET_POL */
+#define WM8990_PLL_LCK_POL                      0x0100  /* PLL_LCK_POL */
+#define WM8990_GPI8_POL                         0x0080  /* GPI8_POL */
+#define WM8990_GPI7_POL                         0x0040  /* GPI7_POL */
+#define WM8990_GPIO6_POL                        0x0020  /* GPIO6_POL */
+#define WM8990_GPIO5_POL                        0x0010  /* GPIO5_POL */
+#define WM8990_GPIO4_POL                        0x0008  /* GPIO4_POL */
+#define WM8990_GPIO3_POL                        0x0004  /* GPIO3_POL */
+#define WM8990_GPIO2_POL                        0x0002  /* GPIO2_POL */
+#define WM8990_GPIO1_POL                        0x0001  /* GPIO1_POL */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_LI12MUTE                         0x0080  /* LI12MUTE */
+#define WM8990_LI12MUTE_BIT                    7
+#define WM8990_LI12ZC                           0x0040  /* LI12ZC */
+#define WM8990_LI12ZC_BIT                      6
+#define WM8990_LIN12VOL_MASK                    0x001F  /* LIN12VOL - [4:0] */
+#define WM8990_LIN12VOL_SHIFT                  0
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_LI34MUTE                         0x0080  /* LI34MUTE */
+#define WM8990_LI34MUTE_BIT                    7
+#define WM8990_LI34ZC                           0x0040  /* LI34ZC */
+#define WM8990_LI34ZC_BIT                      6
+#define WM8990_LIN34VOL_MASK                    0x001F  /* LIN34VOL - [4:0] */
+#define WM8990_LIN34VOL_SHIFT                  0
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_RI12MUTE                         0x0080  /* RI12MUTE */
+#define WM8990_RI12MUTE_BIT                    7
+#define WM8990_RI12ZC                           0x0040  /* RI12ZC */
+#define WM8990_RI12ZC_BIT                      6
+#define WM8990_RIN12VOL_MASK                    0x001F  /* RIN12VOL - [4:0] */
+#define WM8990_RIN12VOL_SHIFT                  0
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8990_IPVU                             0x0100  /* IPVU */
+#define WM8990_RI34MUTE                         0x0080  /* RI34MUTE */
+#define WM8990_RI34MUTE_BIT                    7
+#define WM8990_RI34ZC                           0x0040  /* RI34ZC */
+#define WM8990_RI34ZC_BIT                      6
+#define WM8990_RIN34VOL_MASK                    0x001F  /* RIN34VOL - [4:0] */
+#define WM8990_RIN34VOL_SHIFT                  0
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_LOZC                             0x0080  /* LOZC */
+#define WM8990_LOZC_BIT                                7
+#define WM8990_LOUTVOL_MASK                     0x007F  /* LOUTVOL - [6:0] */
+#define WM8990_LOUTVOL_SHIFT                   0
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_ROZC                             0x0080  /* ROZC */
+#define WM8990_ROZC_BIT                                7
+#define WM8990_ROUTVOL_MASK                     0x007F  /* ROUTVOL - [6:0] */
+#define WM8990_ROUTVOL_SHIFT                   0
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8990_LONMUTE                          0x0040  /* LONMUTE */
+#define WM8990_LONMUTE_BIT                     6
+#define WM8990_LOPMUTE                          0x0020  /* LOPMUTE */
+#define WM8990_LOPMUTE_BIT                     5
+#define WM8990_LOATTN                           0x0010  /* LOATTN */
+#define WM8990_LOATTN_BIT                      4
+#define WM8990_RONMUTE                          0x0004  /* RONMUTE */
+#define WM8990_RONMUTE_BIT                     2
+#define WM8990_ROPMUTE                          0x0002  /* ROPMUTE */
+#define WM8990_ROPMUTE_BIT                     1
+#define WM8990_ROATTN                           0x0001  /* ROATTN */
+#define WM8990_ROATTN_BIT                      0
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8990_OUT3MUTE                         0x0020  /* OUT3MUTE */
+#define WM8990_OUT3MUTE_BIT                    5
+#define WM8990_OUT3ATTN                         0x0010  /* OUT3ATTN */
+#define WM8990_OUT3ATTN_BIT                    4
+#define WM8990_OUT4MUTE                         0x0002  /* OUT4MUTE */
+#define WM8990_OUT4MUTE_BIT                    1
+#define WM8990_OUT4ATTN                         0x0001  /* OUT4ATTN */
+#define WM8990_OUT4ATTN_BIT                    0
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_LOPGAZC                          0x0080  /* LOPGAZC */
+#define WM8990_LOPGAZC_BIT                     7
+#define WM8990_LOPGAVOL_MASK                    0x007F  /* LOPGAVOL - [6:0] */
+#define WM8990_LOPGAVOL_SHIFT                  0
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8990_OPVU                             0x0100  /* OPVU */
+#define WM8990_ROPGAZC                          0x0080  /* ROPGAZC */
+#define WM8990_ROPGAZC_BIT                     7
+#define WM8990_ROPGAVOL_MASK                    0x007F  /* ROPGAVOL - [6:0] */
+#define WM8990_ROPGAVOL_SHIFT                  0
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8990_SPKVOL_MASK                      0x0003  /* SPKVOL - [1:0] */
+#define WM8990_SPKVOL_SHIFT                    0
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8990_CDMODE                           0x0100  /* CDMODE */
+#define WM8990_CDMODE_BIT                      8
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8990_DCGAIN_MASK                      0x0007  /* DCGAIN - [5:3] */
+#define WM8990_DCGAIN_SHIFT                    3
+#define WM8990_ACGAIN_MASK                      0x0007  /* ACGAIN - [2:0] */
+#define WM8990_ACGAIN_SHIFT                    0
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8990_AINLMODE_MASK                    0x000C  /* AINLMODE - [3:2] */
+#define WM8990_AINLMODE_SHIFT                  2
+#define WM8990_AINRMODE_MASK                    0x0003  /* AINRMODE - [1:0] */
+#define WM8990_AINRMODE_SHIFT                  0
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8990_LMP4                            0x0080  /* LMP4 */
+#define WM8990_LMP4_BIT                         7      /* LMP4 */
+#define WM8990_LMN3                             0x0040  /* LMN3 */
+#define WM8990_LMN3_BIT                         6       /* LMN3 */
+#define WM8990_LMP2                             0x0020  /* LMP2 */
+#define WM8990_LMP2_BIT                         5       /* LMP2 */
+#define WM8990_LMN1                             0x0010  /* LMN1 */
+#define WM8990_LMN1_BIT                         4       /* LMN1 */
+#define WM8990_RMP4                             0x0008  /* RMP4 */
+#define WM8990_RMP4_BIT                         3       /* RMP4 */
+#define WM8990_RMN3                             0x0004  /* RMN3 */
+#define WM8990_RMN3_BIT                         2       /* RMN3 */
+#define WM8990_RMP2                             0x0002  /* RMP2 */
+#define WM8990_RMP2_BIT                         1       /* RMP2 */
+#define WM8990_RMN1                             0x0001  /* RMN1 */
+#define WM8990_RMN1_BIT                         0       /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8990_L34MNB                           0x0100  /* L34MNB */
+#define WM8990_L34MNB_BIT                      8
+#define WM8990_L34MNBST                         0x0080  /* L34MNBST */
+#define WM8990_L34MNBST_BIT                    7
+#define WM8990_L12MNB                           0x0020  /* L12MNB */
+#define WM8990_L12MNB_BIT                      5
+#define WM8990_L12MNBST                         0x0010  /* L12MNBST */
+#define WM8990_L12MNBST_BIT                    4
+#define WM8990_LDBVOL_MASK                      0x0007  /* LDBVOL - [2:0] */
+#define WM8990_LDBVOL_SHIFT                    0
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8990_R34MNB                           0x0100  /* R34MNB */
+#define WM8990_R34MNB_BIT                      8
+#define WM8990_R34MNBST                         0x0080  /* R34MNBST */
+#define WM8990_R34MNBST_BIT                    7
+#define WM8990_R12MNB                           0x0020  /* R12MNB */
+#define WM8990_R12MNB_BIT                      5
+#define WM8990_R12MNBST                         0x0010  /* R12MNBST */
+#define WM8990_R12MNBST_BIT                    4
+#define WM8990_RDBVOL_MASK                      0x0007  /* RDBVOL - [2:0] */
+#define WM8990_RDBVOL_SHIFT                    0
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8990_LI2BVOL_MASK                     0x07  /* LI2BVOL - [8:6] */
+#define WM8990_LI2BVOL_SHIFT                   6
+#define WM8990_LR4BVOL_MASK                     0x07  /* LR4BVOL - [5:3] */
+#define WM8990_LR4BVOL_SHIFT                   3
+#define WM8990_LL4BVOL_MASK                     0x07  /* LL4BVOL - [2:0] */
+#define WM8990_LL4BVOL_SHIFT                   0
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8990_RI2BVOL_MASK                     0x07  /* RI2BVOL - [8:6] */
+#define WM8990_RI2BVOL_SHIFT                   6
+#define WM8990_RL4BVOL_MASK                     0x07  /* RL4BVOL - [5:3] */
+#define WM8990_RL4BVOL_SHIFT                   3
+#define WM8990_RR4BVOL_MASK                     0x07  /* RR4BVOL - [2:0] */
+#define WM8990_RR4BVOL_SHIFT                   0
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8990_LRBLO                            0x0080  /* LRBLO */
+#define WM8990_LRBLO_BIT                       7
+#define WM8990_LLBLO                            0x0040  /* LLBLO */
+#define WM8990_LLBLO_BIT                       6
+#define WM8990_LRI3LO                           0x0020  /* LRI3LO */
+#define WM8990_LRI3LO_BIT                      5
+#define WM8990_LLI3LO                           0x0010  /* LLI3LO */
+#define WM8990_LLI3LO_BIT                      4
+#define WM8990_LR12LO                           0x0008  /* LR12LO */
+#define WM8990_LR12LO_BIT                      3
+#define WM8990_LL12LO                           0x0004  /* LL12LO */
+#define WM8990_LL12LO_BIT                      2
+#define WM8990_LDLO                             0x0001  /* LDLO */
+#define WM8990_LDLO_BIT                                0
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8990_RLBRO                            0x0080  /* RLBRO */
+#define WM8990_RLBRO_BIT                       7
+#define WM8990_RRBRO                            0x0040  /* RRBRO */
+#define WM8990_RRBRO_BIT                       6
+#define WM8990_RLI3RO                           0x0020  /* RLI3RO */
+#define WM8990_RLI3RO_BIT                      5
+#define WM8990_RRI3RO                           0x0010  /* RRI3RO */
+#define WM8990_RRI3RO_BIT                      4
+#define WM8990_RL12RO                           0x0008  /* RL12RO */
+#define WM8990_RL12RO_BIT                      3
+#define WM8990_RR12RO                           0x0004  /* RR12RO */
+#define WM8990_RR12RO_BIT                      2
+#define WM8990_RDRO                             0x0001  /* RDRO */
+#define WM8990_RDRO_BIT                                0
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8990_LLI3LOVOL_MASK                   0x07  /* LLI3LOVOL - [8:6] */
+#define WM8990_LLI3LOVOL_SHIFT                 6
+#define WM8990_LR12LOVOL_MASK                   0x07  /* LR12LOVOL - [5:3] */
+#define WM8990_LR12LOVOL_SHIFT                 3
+#define WM8990_LL12LOVOL_MASK                   0x07  /* LL12LOVOL - [2:0] */
+#define WM8990_LL12LOVOL_SHIFT                 0
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8990_RRI3ROVOL_MASK                   0x07  /* RRI3ROVOL - [8:6] */
+#define WM8990_RRI3ROVOL_SHIFT                 6
+#define WM8990_RL12ROVOL_MASK                   0x07  /* RL12ROVOL - [5:3] */
+#define WM8990_RL12ROVOL_SHIFT                 3
+#define WM8990_RR12ROVOL_MASK                   0x07  /* RR12ROVOL - [2:0] */
+#define WM8990_RR12ROVOL_SHIFT                 0
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8990_LRI3LOVOL_MASK                   0x07  /* LRI3LOVOL - [8:6] */
+#define WM8990_LRI3LOVOL_SHIFT                 6
+#define WM8990_LRBLOVOL_MASK                    0x07  /* LRBLOVOL - [5:3] */
+#define WM8990_LRBLOVOL_SHIFT                  3
+#define WM8990_LLBLOVOL_MASK                    0x07  /* LLBLOVOL - [2:0] */
+#define WM8990_LLBLOVOL_SHIFT                  0
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8990_RLI3ROVOL_MASK                   0x07  /* RLI3ROVOL - [8:6] */
+#define WM8990_RLI3ROVOL_SHIFT                 6
+#define WM8990_RLBROVOL_MASK                    0x07  /* RLBROVOL - [5:3] */
+#define WM8990_RLBROVOL_SHIFT                  3
+#define WM8990_RRBROVOL_MASK                    0x07  /* RRBROVOL - [2:0] */
+#define WM8990_RRBROVOL_SHIFT                  0
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8990_VSEL_MASK                        0x0180  /* VSEL - [8:7] */
+#define WM8990_LI4O3                            0x0020  /* LI4O3 */
+#define WM8990_LI4O3_BIT                       5
+#define WM8990_LPGAO3                           0x0010  /* LPGAO3 */
+#define WM8990_LPGAO3_BIT                      4
+#define WM8990_RI4O4                            0x0002  /* RI4O4 */
+#define WM8990_RI4O4_BIT                       1
+#define WM8990_RPGAO4                           0x0001  /* RPGAO4 */
+#define WM8990_RPGAO4_BIT                      0
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8990_LLOPGALON                        0x0040  /* LLOPGALON */
+#define WM8990_LLOPGALON_BIT                   6
+#define WM8990_LROPGALON                        0x0020  /* LROPGALON */
+#define WM8990_LROPGALON_BIT                   5
+#define WM8990_LOPLON                           0x0010  /* LOPLON */
+#define WM8990_LOPLON_BIT                      4
+#define WM8990_LR12LOP                          0x0004  /* LR12LOP */
+#define WM8990_LR12LOP_BIT                     2
+#define WM8990_LL12LOP                          0x0002  /* LL12LOP */
+#define WM8990_LL12LOP_BIT                     1
+#define WM8990_LLOPGALOP                        0x0001  /* LLOPGALOP */
+#define WM8990_LLOPGALOP_BIT                   0
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8990_RROPGARON                        0x0040  /* RROPGARON */
+#define WM8990_RROPGARON_BIT                   6
+#define WM8990_RLOPGARON                        0x0020  /* RLOPGARON */
+#define WM8990_RLOPGARON_BIT                   5
+#define WM8990_ROPRON                           0x0010  /* ROPRON */
+#define WM8990_ROPRON_BIT                      4
+#define WM8990_RL12ROP                          0x0004  /* RL12ROP */
+#define WM8990_RL12ROP_BIT                     2
+#define WM8990_RR12ROP                          0x0002  /* RR12ROP */
+#define WM8990_RR12ROP_BIT                     1
+#define WM8990_RROPGAROP                        0x0001  /* RROPGAROP */
+#define WM8990_RROPGAROP_BIT                   0
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8990_LB2SPK                           0x0080  /* LB2SPK */
+#define WM8990_LB2SPK_BIT                      7
+#define WM8990_RB2SPK                           0x0040  /* RB2SPK */
+#define WM8990_RB2SPK_BIT                      6
+#define WM8990_LI2SPK                           0x0020  /* LI2SPK */
+#define WM8990_LI2SPK_BIT                      5
+#define WM8990_RI2SPK                           0x0010  /* RI2SPK */
+#define WM8990_RI2SPK_BIT                      4
+#define WM8990_LOPGASPK                         0x0008  /* LOPGASPK */
+#define WM8990_LOPGASPK_BIT                    3
+#define WM8990_ROPGASPK                         0x0004  /* ROPGASPK */
+#define WM8990_ROPGASPK_BIT                    2
+#define WM8990_LDSPK                            0x0002  /* LDSPK */
+#define WM8990_LDSPK_BIT                       1
+#define WM8990_RDSPK                            0x0001  /* RDSPK */
+#define WM8990_RDSPK_BIT                       0
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8990_VROI                             0x0001  /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8990_DIS_LLINE                        0x0020  /* DIS_LLINE */
+#define WM8990_DIS_RLINE                        0x0010  /* DIS_RLINE */
+#define WM8990_DIS_OUT3                         0x0008  /* DIS_OUT3 */
+#define WM8990_DIS_OUT4                         0x0004  /* DIS_OUT4 */
+#define WM8990_DIS_LOUT                         0x0002  /* DIS_LOUT */
+#define WM8990_DIS_ROUT                         0x0001  /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8990_SOFTST                           0x0040  /* SOFTST */
+#define WM8990_BUFIOEN                          0x0008  /* BUFIOEN */
+#define WM8990_BUFDCOPEN                        0x0004  /* BUFDCOPEN */
+#define WM8990_POBCTRL                          0x0002  /* POBCTRL */
+#define WM8990_VMIDTOG                          0x0001  /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8990_MCDSCTH_MASK                     0x00C0  /* MCDSCTH - [7:6] */
+#define WM8990_MCDTHR_MASK                      0x0038  /* MCDTHR - [5:3] */
+#define WM8990_MCD                              0x0004  /* MCD */
+#define WM8990_MBSEL                            0x0001  /* MBSEL */
+
+/*
+ * R60 (0x3C) - PLL1
+ */
+#define WM8990_SDM                              0x0080  /* SDM */
+#define WM8990_PRESCALE                         0x0040  /* PRESCALE */
+#define WM8990_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+
+/*
+ * R61 (0x3D) - PLL2
+ */
+#define WM8990_PLLK1_MASK                       0x00FF  /* PLLK1 - [7:0] */
+
+/*
+ * R62 (0x3E) - PLL3
+ */
+#define WM8990_PLLK2_MASK                       0x00FF  /* PLLK2 - [7:0] */
+
+/*
+ * R63 (0x3F) - Internal Driver Bits
+ */
+#define WM8990_INMIXL_PWR_BIT                  0
+#define WM8990_AINLMUX_PWR_BIT                 1
+#define WM8990_INMIXR_PWR_BIT                  2
+#define WM8990_AINRMUX_PWR_BIT                 3
+
+struct wm8990_setup_data {
+       unsigned short i2c_address;
+};
+
+#define WM8990_MCLK_DIV 0
+#define WM8990_DACCLK_DIV 1
+#define WM8990_ADCCLK_DIV 2
+#define WM8990_BCLK_DIV 3
+
+extern struct snd_soc_dai wm8990_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8990;
+
+#endif /* __WM8990REGISTERDEFS_H__ */
+/*------------------------------ END OF FILE ---------------------------------*/
index 76c1e2d33e7d0b8d0b5d22a6dd7dc5fbf7fa37f6..9fc8edd82225cfe98dfbcb6aabadddf48eb1e9c5 100644 (file)
@@ -9,9 +9,6 @@
  *  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.
- *
- *  Revision history
- *    4th Feb 2006   Initial version.
  */
 
 #include <linux/init.h>
@@ -25,6 +22,7 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include "wm9712.h"
 
 #define WM9712_VERSION "0.4"
 
@@ -351,7 +349,7 @@ SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("MIC2"),
 };
 
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
        /* virtual mixer - mixes left & right channels for spk and mono */
        {"AC97 Mixer", NULL, "Left DAC"},
        {"AC97 Mixer", NULL, "Right DAC"},
@@ -446,21 +444,14 @@ static const char *audio_map[][3] = {
        {"Speaker PGA", NULL, "Speaker Mux"},
        {"LOUT2", NULL, "Speaker PGA"},
        {"ROUT2", NULL, "Speaker PGA"},
-
-       {NULL, NULL, NULL},
 };
 
 static int wm9712_add_widgets(struct snd_soc_codec *codec)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets,
+                                 ARRAY_SIZE(wm9712_dapm_widgets));
 
-       /* set up audio path connects */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                                          audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        snd_soc_dapm_new_widgets(codec);
        return 0;
@@ -541,7 +532,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream)
                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000)
 
-struct snd_soc_codec_dai wm9712_dai[] = {
+struct snd_soc_dai wm9712_dai[] = {
 {
        .name = "AC97 HiFi",
        .type = SND_SOC_DAI_AC97_BUS,
@@ -574,23 +565,23 @@ struct snd_soc_codec_dai wm9712_dai[] = {
 };
 EXPORT_SYMBOL_GPL(wm9712_dai);
 
-static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm9712_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
 {
-       switch (event) {
-       case SNDRV_CTL_POWER_D0: /* full On */
-       case SNDRV_CTL_POWER_D1: /* partial On */
-       case SNDRV_CTL_POWER_D2: /* partial On */
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
                break;
-       case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+       case SND_SOC_BIAS_STANDBY:
                ac97_write(codec, AC97_POWERDOWN, 0x0000);
                break;
-       case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+       case SND_SOC_BIAS_OFF:
                /* disable everything including AC link */
                ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm_state = event;
+       codec->bias_level = level;
        return 0;
 }
 
@@ -598,12 +589,12 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
 {
        if (try_warm && soc_ac97_ops.warm_reset) {
                soc_ac97_ops.warm_reset(codec->ac97);
-               if (!(ac97_read(codec, 0) & 0x8000))
+               if (ac97_read(codec, 0) == wm9712_reg[0])
                        return 1;
        }
 
        soc_ac97_ops.reset(codec->ac97);
-       if (ac97_read(codec, 0) & 0x8000)
+       if (ac97_read(codec, 0) != wm9712_reg[0])
                goto err;
        return 0;
 
@@ -618,7 +609,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev,
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->codec;
 
-       wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+       wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
@@ -635,7 +626,7 @@ static int wm9712_soc_resume(struct platform_device *pdev)
                return ret;
        }
 
-       wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        if (ret == 0) {
                /* Sync reg_cache with the hardware after cold reset */
@@ -647,8 +638,8 @@ static int wm9712_soc_resume(struct platform_device *pdev)
                }
        }
 
-       if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
-               wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0);
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+               wm9712_set_bias_level(codec, SND_SOC_BIAS_ON);
 
        return ret;
 }
@@ -682,7 +673,7 @@ static int wm9712_soc_probe(struct platform_device *pdev)
        codec->num_dai = ARRAY_SIZE(wm9712_dai);
        codec->write = ac97_write;
        codec->read = ac97_read;
-       codec->dapm_event = wm9712_dapm_event;
+       codec->set_bias_level = wm9712_set_bias_level;
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
@@ -706,7 +697,7 @@ static int wm9712_soc_probe(struct platform_device *pdev)
        /* set alc mux to none */
        ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
 
-       wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        wm9712_add_controls(codec);
        wm9712_add_widgets(codec);
        ret = snd_soc_register_card(socdev);
index 719105d61e6504c1083e7fdf920251ba075b4575..d29e8a18ca6d2abc6aa67d1c717f571978703a82 100644 (file)
@@ -8,7 +8,7 @@
 #define WM9712_DAI_AC97_HIFI   0
 #define WM9712_DAI_AC97_AUX            1
 
-extern struct snd_soc_codec_dai wm9712_dai[2];
+extern struct snd_soc_dai wm9712_dai[2];
 extern struct snd_soc_codec_device soc_codec_dev_wm9712;
 
 #endif
index 1f241161445ce423135c62adcc9e325d14d4bd05..38d1fe0971fc7faf328c6a19ca0f6f6516f42577 100644 (file)
@@ -10,9 +10,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    4th Feb 2006   Initial version.
- *
  *  Features:-
  *
  *   o Support for AC97 Codec, Voice DAC and Aux DAC
@@ -456,7 +453,7 @@ SND_SOC_DAPM_INPUT("MIC2B"),
 SND_SOC_DAPM_VMID("VMID"),
 };
 
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
        /* left HP mixer */
        {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"},
        {"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
@@ -607,21 +604,14 @@ static const char *audio_map[][3] = {
        {"Capture Mono Mux", "Stereo", "Capture Mixer"},
        {"Capture Mono Mux", "Left", "Left Capture Source"},
        {"Capture Mono Mux", "Right", "Right Capture Source"},
-
-       {NULL, NULL, NULL},
 };
 
 static int wm9713_add_widgets(struct snd_soc_codec *codec)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm9713_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm9713_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm9713_dapm_widgets,
+                                 ARRAY_SIZE(wm9713_dapm_widgets));
 
-       /* set up audio path audio_mapnects */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        snd_soc_dapm_new_widgets(codec);
        return 0;
@@ -799,7 +789,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
+static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai,
                int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -810,7 +800,7 @@ static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
  * Tristate the PCM DAI lines, tristate can be disabled by calling
  * wm9713_set_dai_fmt()
  */
-static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai,
+static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai,
        int tristate)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -826,7 +816,7 @@ static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai,
  * Configure WM9713 clock dividers.
  * Voice DAC needs 256 FS
  */
-static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
+static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                int div_id, int div)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -868,7 +858,7 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
        return 0;
 }
 
-static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -886,7 +876,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
                gpio |= 0x0018;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
-               reg |= 0x0200;
+               reg |= 0x2000;
                gpio |= 0x001a;
                break;
        case SND_SOC_DAIFMT_CBS_CFM:
@@ -1011,15 +1001,24 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream)
        return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate);
 }
 
-#define WM9713_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
-               SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
-               SNDRV_PCM_RATE_48000)
+#define WM9713_RATES (SNDRV_PCM_RATE_8000  |   \
+                     SNDRV_PCM_RATE_11025 |    \
+                     SNDRV_PCM_RATE_22050 |    \
+                     SNDRV_PCM_RATE_44100 |    \
+                     SNDRV_PCM_RATE_48000)
+
+#define WM9713_PCM_RATES (SNDRV_PCM_RATE_8000  |       \
+                         SNDRV_PCM_RATE_11025 |        \
+                         SNDRV_PCM_RATE_16000 |        \
+                         SNDRV_PCM_RATE_22050 |        \
+                         SNDRV_PCM_RATE_44100 |        \
+                         SNDRV_PCM_RATE_48000)
 
 #define WM9713_PCM_FORMATS \
        (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
         SNDRV_PCM_FORMAT_S24_LE)
 
-struct snd_soc_codec_dai wm9713_dai[] = {
+struct snd_soc_dai wm9713_dai[] = {
 {
        .name = "AC97 HiFi",
        .type = SND_SOC_DAI_AC97_BUS,
@@ -1061,13 +1060,13 @@ struct snd_soc_codec_dai wm9713_dai[] = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
                .channels_max = 1,
-               .rates = WM9713_RATES,
+               .rates = WM9713_PCM_RATES,
                .formats = WM9713_PCM_FORMATS,},
        .capture = {
                .stream_name = "Voice Capture",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = WM9713_RATES,
+               .rates = WM9713_PCM_RATES,
                .formats = WM9713_PCM_FORMATS,},
        .ops = {
                .hw_params = wm9713_pcm_hw_params,
@@ -1086,44 +1085,44 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
 {
        if (try_warm && soc_ac97_ops.warm_reset) {
                soc_ac97_ops.warm_reset(codec->ac97);
-               if (!(ac97_read(codec, 0) & 0x8000))
+               if (ac97_read(codec, 0) == wm9713_reg[0])
                        return 1;
        }
 
        soc_ac97_ops.reset(codec->ac97);
-       if (ac97_read(codec, 0) & 0x8000)
+       if (ac97_read(codec, 0) != wm9713_reg[0])
                return -EIO;
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm9713_reset);
 
-static int wm9713_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm9713_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
 {
        u16 reg;
 
-       switch (event) {
-       case SNDRV_CTL_POWER_D0: /* full On */
+       switch (level) {
+       case SND_SOC_BIAS_ON:
                /* enable thermal shutdown */
                reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff;
                ac97_write(codec, AC97_EXTENDED_MID, reg);
                break;
-       case SNDRV_CTL_POWER_D1: /* partial On */
-       case SNDRV_CTL_POWER_D2: /* partial On */
+       case SND_SOC_BIAS_PREPARE:
                break;
-       case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+       case SND_SOC_BIAS_STANDBY:
                /* enable master bias and vmid */
                reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff;
                ac97_write(codec, AC97_EXTENDED_MID, reg);
                ac97_write(codec, AC97_POWERDOWN, 0x0000);
                break;
-       case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+       case SND_SOC_BIAS_OFF:
                /* disable everything including AC link */
                ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
                ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm_state = event;
+       codec->bias_level = level;
        return 0;
 }
 
@@ -1160,7 +1159,7 @@ static int wm9713_soc_resume(struct platform_device *pdev)
                return ret;
        }
 
-       wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* do we need to re-start the PLL ? */
        if (wm9713->pll_out)
@@ -1176,8 +1175,8 @@ static int wm9713_soc_resume(struct platform_device *pdev)
                }
        }
 
-       if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
-               wm9713_dapm_event(codec, SNDRV_CTL_POWER_D0);
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+               wm9713_set_bias_level(codec, SND_SOC_BIAS_ON);
 
        return ret;
 }
@@ -1216,7 +1215,7 @@ static int wm9713_soc_probe(struct platform_device *pdev)
        codec->num_dai = ARRAY_SIZE(wm9713_dai);
        codec->write = ac97_write;
        codec->read = ac97_read;
-       codec->dapm_event = wm9713_dapm_event;
+       codec->set_bias_level = wm9713_set_bias_level;
        INIT_LIST_HEAD(&codec->dapm_widgets);
        INIT_LIST_HEAD(&codec->dapm_paths);
 
@@ -1238,7 +1237,7 @@ static int wm9713_soc_probe(struct platform_device *pdev)
                goto reset_err;
        }
 
-       wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+       wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* unmute the adc - move to kcontrol */
        reg = ac97_read(codec, AC97_CD) & 0x7fff;
index d357b6c8134b7833f13113cd64107fbc8888e85f..63b8d81756e3a50daaeffd777da56539a6f2ad9f 100644 (file)
@@ -46,7 +46,7 @@
 #define WM9713_DAI_PCM_VOICE   2
 
 extern struct snd_soc_codec_device soc_codec_dev_wm9713;
-extern struct snd_soc_codec_dai wm9713_dai[3];
+extern struct snd_soc_dai wm9713_dai[3];
 
 int wm9713_reset(struct snd_soc_codec *codec,  int try_warm);
 
index 20680c551aabc8047fcaf6cd5210dc8914d1736b..8f7e3383490246e81c66c4dc7b92849d768b804e 100644 (file)
@@ -1,6 +1,6 @@
 config SND_DAVINCI_SOC
        tristate "SoC Audio for the TI DAVINCI chip"
-       depends on ARCH_DAVINCI && SND_SOC
+       depends on ARCH_DAVINCI
        help
          Say Y or M if you want to add support for codecs attached to
          the DAVINCI AC97 or I2S interface. You will also need
index fcd165240333ff3e0880164a71657cbe4d54e5b3..5e2c306399edac83170615b47bab77e379113036 100644 (file)
@@ -33,24 +33,24 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int ret = 0;
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                                         SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM |
                                       SND_SOC_DAIFMT_IB_NF);
        if (ret < 0)
                return ret;
 
        /* set the codec system clock */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK,
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK,
                                            SND_SOC_CLOCK_OUT);
        if (ret < 0)
                return ret;
@@ -71,7 +71,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 };
 
 /* davinci-evm machine audio_mapnections to the codec pins */
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
        /* Headphone connected to HPLOUT, HPROUT */
        {"Headphone Jack", NULL, "HPLOUT"},
        {"Headphone Jack", NULL, "HPROUT"},
@@ -90,36 +90,30 @@ static const char *audio_map[][3] = {
        {"LINE2L", NULL, "Line In"},
        {"LINE1R", NULL, "Line In"},
        {"LINE2R", NULL, "Line In"},
-
-       {NULL, NULL, NULL},
 };
 
 /* Logic for a aic3x as connected on a davinci-evm */
 static int evm_aic3x_init(struct snd_soc_codec *codec)
 {
-       int i;
-
        /* Add davinci-evm specific widgets */
-       for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+                                 ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* Set up davinci-evm specific audio path audio_map */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                                          audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        /* not connected */
-       snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0);
-       snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0);
-       snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0);
+       snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
+       snd_soc_dapm_disable_pin(codec, "HPLCOM");
+       snd_soc_dapm_disable_pin(codec, "HPRCOM");
 
        /* always connected */
-       snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
-       snd_soc_dapm_set_endpoint(codec, "Line Out", 1);
-       snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
-       snd_soc_dapm_set_endpoint(codec, "Line In", 1);
+       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+       snd_soc_dapm_enable_pin(codec, "Line Out");
+       snd_soc_dapm_enable_pin(codec, "Mic Jack");
+       snd_soc_dapm_enable_pin(codec, "Line In");
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 
        return 0;
 }
index c421774b33ee9b58d9705ada66e546bd4ba9fce9..5ebf1ff71c4cbce6451ecd63dbe080586ac531ea 100644 (file)
@@ -147,7 +147,7 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream)
 static int davinci_i2s_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
 
        cpu_dai->dma_data = dev->dma_params[substream->stream];
@@ -155,7 +155,7 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int davinci_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                   unsigned int fmt)
 {
        struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
@@ -295,11 +295,12 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
        return ret;
 }
 
-static int davinci_i2s_probe(struct platform_device *pdev)
+static int davinci_i2s_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_machine *machine = socdev->machine;
-       struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
+       struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
        struct davinci_mcbsp_dev *dev;
        struct resource *mem, *ioarea;
        struct evm_snd_platform_data *pdata;
@@ -356,11 +357,12 @@ err_release_region:
        return ret;
 }
 
-static void davinci_i2s_remove(struct platform_device *pdev)
+static void davinci_i2s_remove(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
 {
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_machine *machine = socdev->machine;
-       struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
+       struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai;
        struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
        struct resource *mem;
 
@@ -376,7 +378,7 @@ static void davinci_i2s_remove(struct platform_device *pdev)
 
 #define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
-struct snd_soc_cpu_dai davinci_i2s_dai = {
+struct snd_soc_dai davinci_i2s_dai = {
        .name = "davinci-i2s",
        .id = 0,
        .type = SND_SOC_DAI_I2S,
index 9592d17db320c88524901eebcf6da5ef9bb518fc..c5b091807eecf891bb71baa1a208933da3c62a17 100644 (file)
@@ -12,6 +12,6 @@
 #ifndef _DAVINCI_I2S_H
 #define _DAVINCI_I2S_H
 
-extern struct snd_soc_cpu_dai davinci_i2s_dai;
+extern struct snd_soc_dai davinci_i2s_dai;
 
 #endif
index 6a76927c997144c4d6dcbd1e0e317c7d39c82c62..6a5e56a782bb2f9a13551aa3365a6b2b7db85e4a 100644 (file)
@@ -350,7 +350,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
 static u64 davinci_pcm_dmamask = 0xffffffff;
 
 static int davinci_pcm_new(struct snd_card *card,
-                          struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
+                          struct snd_soc_dai *dai, struct snd_pcm *pcm)
 {
        int ret;
 
index 257101f44e9e168de81dcbd2429b740b8c699954..3368ace60977eac389f1b57254e3fcb6c832ab4d 100644 (file)
@@ -1,8 +1,6 @@
-menu "ALSA SoC audio for Freescale SOCs"
-
 config SND_SOC_MPC8610
        bool "ALSA SoC support for the MPC8610 SOC"
-       depends on SND_SOC && MPC8610_HPCD
+       depends on MPC8610_HPCD
        default y if MPC8610
        help
          Say Y if you want to add support for codecs attached to the SSI
@@ -16,5 +14,3 @@ config SND_SOC_MPC8610_HPCD
        default y if MPC8610_HPCD
        help
          Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
-
-endmenu
index 78de7168d2ba506c767c397f6362ae0c248ef190..da2bc590286438fe7b000cea43e24baf4b6bb417 100644 (file)
@@ -282,7 +282,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
  * once for each .dai_link in the machine driver's snd_soc_machine
  * structure.
  */
-static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
        static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
index 430a6ce8b0d0964f1c2591b07463e4c2e6d6b255..385d4a42603cf3b681ab12c6f050ccd3e11f7bb0 100644 (file)
@@ -126,7 +126,7 @@ struct fsl_dma_link_descriptor {
        u8 res[4];      /* Reserved */
 } __attribute__ ((aligned(32), packed));
 
-/* DMA information needed to create a snd_soc_cpu_dai object
+/* DMA information needed to create a snd_soc_dai object
  *
  * ssi_stx_phys: bus address of SSI STX register to use
  * ssi_srx_phys: bus address of SSI SRX register to use
index f588545698f3687f75941977b8e597791c964e9e..71bff33f5528fe5e34849c06bbc1e88b91fbbcbb 100644 (file)
@@ -82,7 +82,7 @@ struct fsl_ssi_private {
        struct device *dev;
        unsigned int playback;
        unsigned int capture;
-       struct snd_soc_cpu_dai cpu_dai;
+       struct snd_soc_dai cpu_dai;
        struct device_attribute dev_attr;
 
        struct {
@@ -479,7 +479,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
  * @freq: the frequency of the given clock ID, currently ignored
  * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
  */
-static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
                              int clk_id, unsigned int freq, int dir)
 {
 
@@ -497,7 +497,7 @@ static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
  *
  * @format: one of SND_SOC_DAIFMT_xxx
  */
-static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format)
+static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 {
        return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
 }
@@ -505,7 +505,7 @@ static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format)
 /**
  * fsl_ssi_dai_template: template CPU DAI for the SSI
  */
-static struct snd_soc_cpu_dai fsl_ssi_dai_template = {
+static struct snd_soc_dai fsl_ssi_dai_template = {
        .playback = {
                /* The SSI does not support monaural audio. */
                .channels_min = 2,
@@ -569,15 +569,15 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev,
 }
 
 /**
- * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure
+ * fsl_ssi_create_dai: create a snd_soc_dai structure
  *
- * This function is called by the machine driver to create a snd_soc_cpu_dai
+ * This function is called by the machine driver to create a snd_soc_dai
  * structure.  The function creates an ssi_private object, which contains
- * the snd_soc_cpu_dai.  It also creates the sysfs statistics device.
+ * the snd_soc_dai.  It also creates the sysfs statistics device.
  */
-struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
+struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
 {
-       struct snd_soc_cpu_dai *fsl_ssi_dai;
+       struct snd_soc_dai *fsl_ssi_dai;
        struct fsl_ssi_private *ssi_private;
        int ret = 0;
        struct device_attribute *dev_attr;
@@ -588,7 +588,7 @@ struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
                return NULL;
        }
        memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
-              sizeof(struct snd_soc_cpu_dai));
+              sizeof(struct snd_soc_dai));
 
        fsl_ssi_dai = &ssi_private->cpu_dai;
        dev_attr = &ssi_private->dev_attr;
@@ -623,11 +623,11 @@ struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
 EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
 
 /**
- * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object
+ * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
  *
  * This function undoes the operations of fsl_ssi_create_dai()
  */
-void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai)
+void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
 {
        struct fsl_ssi_private *ssi_private =
        container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
index c5ce88e1565190ae5acd6322c71f665c4850d761..83b44d700e3328fbf973d25c616751555211f202 100644 (file)
@@ -217,8 +217,8 @@ struct fsl_ssi_info {
        struct device *dev;
 };
 
-struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
-void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai);
+struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
+void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai);
 
 #endif
 
index a00aac7a71f1c10e88b681e4867647bf96d9c328..4bdc9d8fc90e0d8fa3f4f7d6d5f14813c4abe5da 100644 (file)
@@ -58,9 +58,9 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
                sound_device->dev.platform_data;
 
        /* Program the signal routing between the SSI and the DMA */
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
                machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
                machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
 
        guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
@@ -96,62 +96,52 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
 static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct mpc8610_hpcd_data *machine_data =
                rtd->socdev->dev->platform_data;
        int ret = 0;
 
        /* Tell the CPU driver what the serial protocol is. */
-       if (cpu_dai->dai_ops.set_fmt) {
-               ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
-                       machine_data->dai_format);
-               if (ret < 0) {
-                       dev_err(substream->pcm->card->dev,
-                               "could not set CPU driver audio format\n");
-                       return ret;
-               }
+       ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev,
+                       "could not set CPU driver audio format\n");
+               return ret;
        }
 
        /* Tell the codec driver what the serial protocol is. */
-       if (codec_dai->dai_ops.set_fmt) {
-               ret = codec_dai->dai_ops.set_fmt(codec_dai,
-                       machine_data->dai_format);
-               if (ret < 0) {
-                       dev_err(substream->pcm->card->dev,
-                               "could not set codec driver audio format\n");
-                       return ret;
-               }
+       ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev,
+                       "could not set codec driver audio format\n");
+               return ret;
        }
 
        /*
         * Tell the CPU driver what the clock frequency is, and whether it's a
         * slave or master.
         */
-       if (cpu_dai->dai_ops.set_sysclk) {
-               ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0,
-                       machine_data->clk_frequency,
-                       machine_data->cpu_clk_direction);
-               if (ret < 0) {
-                       dev_err(substream->pcm->card->dev,
-                               "could not set CPU driver clock parameters\n");
-                       return ret;
-               }
+       ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
+                                       machine_data->clk_frequency,
+                                       machine_data->cpu_clk_direction);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev,
+                       "could not set CPU driver clock parameters\n");
+               return ret;
        }
 
        /*
         * Tell the codec driver what the MCLK frequency is, and whether it's
         * a slave or master.
         */
-       if (codec_dai->dai_ops.set_sysclk) {
-               ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0,
-                       machine_data->clk_frequency,
-                       machine_data->codec_clk_direction);
-               if (ret < 0) {
-                       dev_err(substream->pcm->card->dev,
-                               "could not set codec driver clock params\n");
-                       return ret;
-               }
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+                                       machine_data->clk_frequency,
+                                       machine_data->codec_clk_direction);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev,
+                       "could not set codec driver clock params\n");
+               return ret;
        }
 
        return 0;
@@ -170,9 +160,9 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
 
        /* Restore the signal routing */
 
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
                machine_data->dma_channel_id[0], 0);
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
                machine_data->dma_channel_id[1], 0);
 
        switch (machine_data->ssi_id) {
@@ -182,7 +172,7 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
                break;
        case 1:
                clrsetbits_be32(&machine_data->guts->pmuxcr,
-                       CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
+                       CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
                break;
        }
 
index 0230d83e8e5ef83739f1f4ae4c602e2cffc392ae..aea27e70043cf8f687884227c117ceed224c98f4 100644 (file)
@@ -1,5 +1,3 @@
-menu "SoC Audio for the Texas Instruments OMAP"
-
 config SND_OMAP_SOC
        tristate "SoC Audio for the Texas Instruments OMAP chips"
        depends on ARCH_OMAP && SND_SOC
@@ -15,5 +13,3 @@ config SND_OMAP_SOC_N810
        select SND_SOC_TLV320AIC3X
        help
          Say Y if you want to add support for SoC audio on Nokia N810.
-
-endmenu
index 6533563a6011d01ccb71084c136f79d7a1b808d6..02cec96859b8444133a1cf3a464533bdd87c67cf 100644 (file)
 
 #include <asm/mach-types.h>
 #include <asm/arch/hardware.h>
-#include <asm/arch/gpio.h>
+#include <linux/gpio.h>
 #include <asm/arch/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
 #include "../codecs/tlv320aic3x.h"
 
-#define RX44_HEADSET_AMP_GPIO  10
-#define RX44_SPEAKER_AMP_GPIO  101
+#define N810_HEADSET_AMP_GPIO  10
+#define N810_SPEAKER_AMP_GPIO  101
 
 static struct clk *sys_clkout2;
 static struct clk *sys_clkout2_src;
@@ -46,13 +46,26 @@ static struct clk *func96m_clk;
 
 static int n810_spk_func;
 static int n810_jack_func;
+static int n810_dmic_func;
 
 static void n810_ext_control(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func);
-       snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func);
+       if (n810_spk_func)
+               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+       else
+               snd_soc_dapm_disable_pin(codec, "Ext Spk");
+
+       if (n810_jack_func)
+               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+       else
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
 
-       snd_soc_dapm_sync_endpoints(codec);
+       if (n810_dmic_func)
+               snd_soc_dapm_enable_pin(codec, "DMic");
+       else
+               snd_soc_dapm_disable_pin(codec, "DMic");
+
+       snd_soc_dapm_sync(codec);
 }
 
 static int n810_startup(struct snd_pcm_substream *substream)
@@ -73,12 +86,12 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
-       err = codec_dai->dai_ops.set_fmt(codec_dai,
+       err = snd_soc_dai_set_fmt(codec_dai,
                                         SND_SOC_DAIFMT_I2S |
                                         SND_SOC_DAIFMT_NB_NF |
                                         SND_SOC_DAIFMT_CBM_CFM);
@@ -86,7 +99,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        /* Set cpu DAI configuration */
-       err = cpu_dai->dai_ops.set_fmt(cpu_dai,
+       err = snd_soc_dai_set_fmt(cpu_dai,
                                       SND_SOC_DAIFMT_I2S |
                                       SND_SOC_DAIFMT_NB_NF |
                                       SND_SOC_DAIFMT_CBM_CFM);
@@ -94,7 +107,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        /* Set the codec system clock for DAC and ADC */
-       err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000,
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
                                            SND_SOC_CLOCK_IN);
 
        return err;
@@ -150,13 +163,35 @@ static int n810_set_jack(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
+static int n810_get_input(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = n810_dmic_func;
+
+       return 0;
+}
+
+static int n810_set_input(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+
+       if (n810_dmic_func == ucontrol->value.integer.value[0])
+               return 0;
+
+       n810_dmic_func = ucontrol->value.integer.value[0];
+       n810_ext_control(codec);
+
+       return 1;
+}
+
 static int n810_spk_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *k, int event)
 {
        if (SND_SOC_DAPM_EVENT_ON(event))
-               omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 1);
+               gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
        else
-               omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 0);
+               gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
 
        return 0;
 }
@@ -165,9 +200,9 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *k, int event)
 {
        if (SND_SOC_DAPM_EVENT_ON(event))
-               omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 1);
+               gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
        else
-               omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 0);
+               gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
 
        return 0;
 }
@@ -175,21 +210,27 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w,
 static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
        SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
        SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
+       SND_SOC_DAPM_MIC("DMic", NULL),
 };
 
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
        {"Headphone Jack", NULL, "HPLOUT"},
        {"Headphone Jack", NULL, "HPROUT"},
 
        {"Ext Spk", NULL, "LLOUT"},
        {"Ext Spk", NULL, "RLOUT"},
+
+       {"DMic Rate 64", NULL, "Mic Bias 2V"},
+       {"Mic Bias 2V", NULL, "DMic"},
 };
 
 static const char *spk_function[] = {"Off", "On"};
 static const char *jack_function[] = {"Off", "Headphone"};
+static const char *input_function[] = {"ADC", "Digital Mic"};
 static const struct soc_enum n810_enum[] = {
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
 };
 
 static const struct snd_kcontrol_new aic33_n810_controls[] = {
@@ -197,6 +238,8 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
                     n810_get_spk, n810_set_spk),
        SOC_ENUM_EXT("Jack Function", n810_enum[1],
                     n810_get_jack, n810_set_jack),
+       SOC_ENUM_EXT("Input Select",  n810_enum[2],
+                    n810_get_input, n810_set_input),
 };
 
 static int n810_aic33_init(struct snd_soc_codec *codec)
@@ -204,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
        int i, err;
 
        /* Not connected */
-       snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0);
-       snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0);
-       snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0);
+       snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
+       snd_soc_dapm_disable_pin(codec, "HPLCOM");
+       snd_soc_dapm_disable_pin(codec, "HPRCOM");
 
        /* Add N810 specific controls */
        for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
@@ -217,15 +260,13 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
        }
 
        /* Add N810 specific widgets */
-       for (i = 0; i < ARRAY_SIZE(aic33_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &aic33_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, aic33_dapm_widgets,
+                                 ARRAY_SIZE(aic33_dapm_widgets));
 
        /* Set up N810 specific audio path audio_map */
-       for (i = 0; i < ARRAY_SIZE(audio_map); i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 
        return 0;
 }
@@ -250,6 +291,8 @@ static struct snd_soc_machine snd_soc_machine_n810 = {
 /* Audio private data */
 static struct aic3x_setup_data n810_aic33_setup = {
        .i2c_address = 0x18,
+       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
 };
 
 /* Audio subsystem */
@@ -267,7 +310,7 @@ static int __init n810_soc_init(void)
        int err;
        struct device *dev;
 
-       if (!machine_is_nokia_n810())
+       if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
                return -ENODEV;
 
        n810_snd_device = platform_device_alloc("soc-audio", -1);
@@ -305,12 +348,12 @@ static int __init n810_soc_init(void)
        clk_set_parent(sys_clkout2_src, func96m_clk);
        clk_set_rate(sys_clkout2, 12000000);
 
-       if (omap_request_gpio(RX44_HEADSET_AMP_GPIO) < 0)
+       if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0)
                BUG();
-       if (omap_request_gpio(RX44_SPEAKER_AMP_GPIO) < 0)
+       if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)
                BUG();
-       omap_set_gpio_direction(RX44_HEADSET_AMP_GPIO, 0);
-       omap_set_gpio_direction(RX44_SPEAKER_AMP_GPIO, 0);
+       gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
+       gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
 
        return 0;
 err2:
@@ -325,6 +368,9 @@ err1:
 
 static void __exit n810_soc_exit(void)
 {
+       gpio_free(N810_SPEAKER_AMP_GPIO);
+       gpio_free(N810_HEADSET_AMP_GPIO);
+
        platform_device_unregister(n810_snd_device);
 }
 
index 40d87e6d0de8672f7463328de6b112805d36eab5..00b0c9d73cd4ee7460f1260c32efae8d31e5bf18 100644 (file)
@@ -103,7 +103,7 @@ static const unsigned long omap2420_mcbsp_port[][2] = {};
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
        int err = 0;
 
@@ -116,7 +116,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 
        if (!cpu_dai->active) {
@@ -128,7 +128,7 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream)
 static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
        int err = 0;
 
@@ -157,7 +157,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
@@ -223,7 +223,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
  * This must be called before _set_clkdiv and _set_sysclk since McBSP register
  * cache is initialized here
  */
-static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                      unsigned int fmt)
 {
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
@@ -292,7 +292,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
        return 0;
 }
 
-static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                     int div_id, int div)
 {
        struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
@@ -347,7 +347,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
        return 0;
 }
 
-static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                         int clk_id, unsigned int freq,
                                         int dir)
 {
@@ -376,7 +376,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
        return err;
 }
 
-struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS] = {
+struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
 {
        .name = "omap-mcbsp-dai",
        .id = 0,
index 9965fd4b042708f581ac76f073864bf8479cc7c5..ed8afb55067173fc4969b2984ae20e10f5cabdea 100644 (file)
@@ -44,6 +44,6 @@ enum omap_mcbsp_div {
  */
 #define NUM_LINKS      1
 
-extern struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS];
+extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
 
 #endif
index 62370202c649c5aac50e542626b574a7079909e2..e092f3d836d0a080a2579f4a93aa0237dd6cc1d3 100644 (file)
@@ -316,7 +316,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-int omap_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                 struct snd_pcm *pcm)
 {
        int ret = 0;
index 484f883459e086a95af2ff2edd881b8c8b9a0500..12f6ac99b04c4386b28f68cbcbe3d404b5cc2efe 100644 (file)
@@ -1,6 +1,6 @@
 config SND_PXA2XX_SOC
        tristate "SoC Audio for the Intel PXA2xx chip"
-       depends on ARCH_PXA && SND_SOC
+       depends on ARCH_PXA
        help
          Say Y or M if you want to add support for codecs attached to
          the PXA2xx AC97, I2S or SSP interface. You will also need
@@ -62,3 +62,12 @@ config SND_PXA2XX_SOC_E800
        help
          Say Y if you want to add support for SoC audio on the
          Toshiba e800 PDA
+
+config SND_PXA2XX_SOC_EM_X270
+       tristate "SoC Audio support for CompuLab EM-x270"
+       depends on SND_PXA2XX_SOC && MACH_EM_X270
+       select SND_PXA2XX_SOC_AC97
+       select SND_SOC_WM9712
+       help
+         Say Y if you want to add support for SoC audio on
+         CompuLab EM-x270.
index 04e5646f75ba3f8d77cc5a0caf4d162439c87b53..5bc8edf9dca9ec8532ec6e56e1c7e7ea88f463fc 100644 (file)
@@ -13,10 +13,11 @@ snd-soc-poodle-objs := poodle.o
 snd-soc-tosa-objs := tosa.o
 snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
+snd-soc-em-x270-objs := em-x270.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
 obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
 obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
-
+obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
index 7f32a1167572c7cf67171a0468f0174cfb4da682..c0294464a23aef4f14c099b989dc058168b4da6a 100644 (file)
  *  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.
- *
- *  Revision history
- *    30th Nov 2005   Initial version.
- *
  */
 
 #include <linux/module.h>
@@ -54,47 +50,51 @@ static int corgi_spk_func;
 
 static void corgi_ext_control(struct snd_soc_codec *codec)
 {
-       int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
-
        /* set up jack connection */
        switch (corgi_jack_func) {
        case CORGI_HP:
-               hp = 1;
                /* set = unmute headphone */
                set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
                set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+               snd_soc_dapm_disable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
                break;
        case CORGI_MIC:
-               mic = 1;
                /* reset = mute headphone */
                reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
                reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+               snd_soc_dapm_enable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
                break;
        case CORGI_LINE:
-               line = 1;
                reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
                reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+               snd_soc_dapm_disable_pin(codec, "Mic Jack");
+               snd_soc_dapm_enable_pin(codec, "Line Jack");
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
                break;
        case CORGI_HEADSET:
-               hs = 1;
-               mic = 1;
                reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
                set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
+               snd_soc_dapm_enable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_enable_pin(codec, "Headset Jack");
                break;
        }
 
        if (corgi_spk_func == CORGI_SPK_ON)
-               spk = 1;
-
-       /* set the enpoints to their new connetion states */
-       snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
-       snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
-       snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
-       snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
-       snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
+               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+       else
+               snd_soc_dapm_disable_pin(codec, "Ext Spk");
 
        /* signal a DAPM event */
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 }
 
 static int corgi_startup(struct snd_pcm_substream *substream)
@@ -123,8 +123,8 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -143,25 +143,25 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
        /* set the I2S system clock as input (unused) */
-       ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -247,7 +247,7 @@ SND_SOC_DAPM_HP("Headset Jack", NULL),
 };
 
 /* Corgi machine audio map (connections to the codec pins) */
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
 
        /* headset Jack  - in = micin, out = LHPOUT*/
        {"Headset Jack", NULL, "LHPOUT"},
@@ -265,8 +265,6 @@ static const char *audio_map[][3] = {
 
        /* Same as the above but no mic bias for line signals */
        {"MICIN", NULL, "Line Jack"},
-
-       {NULL, NULL, NULL},
 };
 
 static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
@@ -291,8 +289,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
-       snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
+       snd_soc_dapm_disable_pin(codec, "LLINEIN");
+       snd_soc_dapm_disable_pin(codec, "RLINEIN");
 
        /* Add corgi specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
@@ -303,15 +301,13 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
        }
 
        /* Add corgi specific widgets */
-       for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
+                                 ARRAY_SIZE(wm8731_dapm_widgets));
 
        /* Set up corgi specific audio path audio_map */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
        return 0;
 }
 
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c
new file mode 100644 (file)
index 0000000..02dcac3
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * em-x270.c  --  SoC audio for EM-X270
+ *
+ * Copyright 2007 CompuLab, Ltd.
+ *
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copied from tosa.c:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm9712.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static struct snd_soc_dai_link em_x270_dai[] = {
+       {
+               .name = "AC97",
+               .stream_name = "AC97 HiFi",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+       },
+       {
+               .name = "AC97 Aux",
+               .stream_name = "AC97 Aux",
+               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       },
+};
+
+static struct snd_soc_machine em_x270 = {
+       .name = "EM-X270",
+       .dai_link = em_x270_dai,
+       .num_links = ARRAY_SIZE(em_x270_dai),
+};
+
+static struct snd_soc_device em_x270_snd_devdata = {
+       .machine = &em_x270,
+       .platform = &pxa2xx_soc_platform,
+       .codec_dev = &soc_codec_dev_wm9712,
+};
+
+static struct platform_device *em_x270_snd_device;
+
+static int __init em_x270_init(void)
+{
+       int ret;
+
+       if (!machine_is_em_x270())
+               return -ENODEV;
+
+       em_x270_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!em_x270_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata);
+       em_x270_snd_devdata.dev = &em_x270_snd_device->dev;
+       ret = platform_device_add(em_x270_snd_device);
+
+       if (ret)
+               platform_device_put(em_x270_snd_device);
+
+       return ret;
+}
+
+static void __exit em_x270_exit(void)
+{
+       platform_device_unregister(em_x270_snd_device);
+}
+
+module_init(em_x270_init);
+module_exit(em_x270_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mike Rapoport");
+MODULE_DESCRIPTION("ALSA SoC EM-X270");
+MODULE_LICENSE("GPL");
index 7e830b218943e90090cebddbedd4cc6ec511bba8..65a4e9a8c39e18ec4dc0b45f44dd780ff6c54b36 100644 (file)
@@ -48,8 +48,6 @@ static int poodle_spk_func;
 
 static void poodle_ext_control(struct snd_soc_codec *codec)
 {
-       int spk = 0;
-
        /* set up jack connection */
        if (poodle_jack_func == POODLE_HP) {
                /* set = unmute headphone */
@@ -57,23 +55,23 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
                        POODLE_LOCOMO_GPIO_MUTE_L, 1);
                locomo_gpio_write(&poodle_locomo_device.dev,
                        POODLE_LOCOMO_GPIO_MUTE_R, 1);
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
        } else {
                locomo_gpio_write(&poodle_locomo_device.dev,
                        POODLE_LOCOMO_GPIO_MUTE_L, 0);
                locomo_gpio_write(&poodle_locomo_device.dev,
                        POODLE_LOCOMO_GPIO_MUTE_R, 0);
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
        }
 
-       if (poodle_spk_func == POODLE_SPK_ON)
-               spk = 1;
-
        /* set the enpoints to their new connetion states */
-       snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
+       if (poodle_spk_func == POODLE_SPK_ON)
+               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+       else
+               snd_soc_dapm_disable_pin(codec, "Ext Spk");
 
        /* signal a DAPM event */
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 }
 
 static int poodle_startup(struct snd_pcm_substream *substream)
@@ -104,8 +102,8 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -124,25 +122,25 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
        /* set the I2S system clock as input (unused) */
-       ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -215,8 +213,8 @@ SND_SOC_DAPM_HP("Headphone Jack", NULL),
 SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
 };
 
-/* Corgi machine audio_mapnections to the codec pins */
-static const char *audio_map[][3] = {
+/* Corgi machine connections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
 
        /* headphone connected to LHPOUT1, RHPOUT1 */
        {"Headphone Jack", NULL, "LHPOUT"},
@@ -225,8 +223,6 @@ static const char *audio_map[][3] = {
        /* speaker connected to LOUT, ROUT */
        {"Ext Spk", NULL, "ROUT"},
        {"Ext Spk", NULL, "LOUT"},
-
-       {NULL, NULL, NULL},
 };
 
 static const char *jack_function[] = {"Off", "Headphone"};
@@ -250,9 +246,9 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
-       snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
-       snd_soc_dapm_set_endpoint(codec, "MICIN", 1);
+       snd_soc_dapm_disable_pin(codec, "LLINEIN");
+       snd_soc_dapm_disable_pin(codec, "RLINEIN");
+       snd_soc_dapm_enable_pin(codec, "MICIN");
 
        /* Add poodle specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) {
@@ -263,15 +259,13 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
        }
 
        /* Add poodle specific widgets */
-       for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
+                                 ARRAY_SIZE(wm8731_dapm_widgets));
 
        /* Set up poodle specific audio path audio_map */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
        return 0;
 }
 
index 97ec2d90547c30e64a177f9f250168d02073d6c0..059af815ea0c65f449d31ea9aa73dee1c86a27ac 100644 (file)
@@ -283,7 +283,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
 
 #ifdef CONFIG_PM
 static int pxa2xx_ac97_suspend(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *dai)
+       struct snd_soc_dai *dai)
 {
        GCR |= GCR_ACLINK_OFF;
        clk_disable(ac97_clk);
@@ -291,7 +291,7 @@ static int pxa2xx_ac97_suspend(struct platform_device *pdev,
 }
 
 static int pxa2xx_ac97_resume(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *dai)
+       struct snd_soc_dai *dai)
 {
        pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
        pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
@@ -310,7 +310,8 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev,
 #define pxa2xx_ac97_resume     NULL
 #endif
 
-static int pxa2xx_ac97_probe(struct platform_device *pdev)
+static int pxa2xx_ac97_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
 {
        int ret;
 
@@ -355,7 +356,8 @@ static int pxa2xx_ac97_probe(struct platform_device *pdev)
        return ret;
 }
 
-static void pxa2xx_ac97_remove(struct platform_device *pdev)
+static void pxa2xx_ac97_remove(struct platform_device *pdev,
+                              struct snd_soc_dai *dai)
 {
        GCR |= GCR_ACLINK_OFF;
        free_irq(IRQ_AC97, NULL);
@@ -372,7 +374,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out;
@@ -386,7 +388,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out;
@@ -400,7 +402,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
@@ -418,7 +420,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
  * There is only 1 physical AC97 interface for pxa2xx, but it
  * has extra fifo's that can be used for aux DACs and ADCs.
  */
-struct snd_soc_cpu_dai pxa_ac97_dai[] = {
+struct snd_soc_dai pxa_ac97_dai[] = {
 {
        .name = "pxa2xx-ac97",
        .id = 0,
index b8ccfee095c4711ce17b0fc80176d5b9d409da28..e390de8edcd48724558f63c4338a9e83b19d1762 100644 (file)
@@ -14,7 +14,7 @@
 #define PXA2XX_DAI_AC97_AUX            1
 #define PXA2XX_DAI_AC97_MIC            2
 
-extern struct snd_soc_cpu_dai pxa_ac97_dai[3];
+extern struct snd_soc_dai pxa_ac97_dai[3];
 
 /* platform data */
 extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
index 425071030970bf07fae6f50b3d863cf89d7c9022..9c06553b92674436619cd0261d19f410e6764f79 100644 (file)
@@ -9,9 +9,6 @@
  *  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.
- *
- *  Revision history
- *    12th Aug 2005   Initial version.
  */
 
 #include <linux/init.h>
@@ -80,7 +77,7 @@ static struct pxa2xx_gpio gpio_bus[] = {
 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        if (!cpu_dai->active) {
                SACR0 |= SACR0_RST;
@@ -101,7 +98,7 @@ static int pxa_i2s_wait(void)
        return 0;
 }
 
-static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
        /* interface format */
@@ -127,7 +124,7 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
        return 0;
 }
 
-static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int dir)
 {
        if (clk_id != PXA2XX_I2S_SYSCLK)
@@ -143,7 +140,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
        pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
@@ -240,7 +237,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
 
 #ifdef CONFIG_PM
 static int pxa2xx_i2s_suspend(struct platform_device *dev,
-       struct snd_soc_cpu_dai *dai)
+       struct snd_soc_dai *dai)
 {
        if (!dai->active)
                return 0;
@@ -258,7 +255,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev,
 }
 
 static int pxa2xx_i2s_resume(struct platform_device *pdev,
-       struct snd_soc_cpu_dai *dai)
+       struct snd_soc_dai *dai)
 {
        if (!dai->active)
                return 0;
@@ -283,7 +280,7 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 
-struct snd_soc_cpu_dai pxa_i2s_dai = {
+struct snd_soc_dai pxa_i2s_dai = {
        .name = "pxa2xx-i2s",
        .id = 0,
        .type = SND_SOC_DAI_I2S,
index 4435bd9f884faec12ab5532c43f5ba687f638367..e2def441153eee706ab6789a00385c6e13f49284 100644 (file)
@@ -15,6 +15,6 @@
 /* I2S clock */
 #define PXA2XX_I2S_SYSCLK              0
 
-extern struct snd_soc_cpu_dai pxa_i2s_dai;
+extern struct snd_soc_dai pxa_i2s_dai;
 
 #endif
index 01ad7bf716b7b03f95f99157cabece01d16d67bd..2df03ee5819ec7ae44b38e1e47955b1983fce247 100644 (file)
@@ -330,7 +330,7 @@ static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK;
 
-int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
        int ret = 0;
index d8b8372db00e76c9412364867025628f3b8d957e..64385797da5d3e0c959c737eaea442e22c0778f0 100644 (file)
@@ -12,9 +12,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    30th Nov 2005   Initial version.
- *
  */
 
 #include <linux/module.h>
@@ -54,60 +51,60 @@ static int spitz_spk_func;
 static void spitz_ext_control(struct snd_soc_codec *codec)
 {
        if (spitz_spk_func == SPITZ_SPK_ON)
-               snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+               snd_soc_dapm_enable_pin(codec, "Ext Spk");
        else
-               snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0);
+               snd_soc_dapm_disable_pin(codec, "Ext Spk");
 
        /* set up jack connection */
        switch (spitz_jack_func) {
        case SPITZ_HP:
                /* enable and unmute hp jack, disable mic bias */
-               snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
                set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
                set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
                break;
        case SPITZ_MIC:
                /* enable mic jack and bias, mute hp */
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_enable_pin(codec, "Mic Jack");
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
                break;
        case SPITZ_LINE:
                /* enable line jack, disable mic bias and mute hp */
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Line Jack", 1);
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(codec, "Mic Jack");
+               snd_soc_dapm_enable_pin(codec, "Line Jack");
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
                break;
        case SPITZ_HEADSET:
                /* enable and unmute headset jack enable mic bias, mute L hp */
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
-               snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1);
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_enable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_enable_pin(codec, "Headset Jack");
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
                set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
                break;
        case SPITZ_HP_OFF:
 
                /* jack removed, everything off */
-               snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
-               snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(codec, "Line Jack");
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
                reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
                break;
        }
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 }
 
 static int spitz_startup(struct snd_pcm_substream *substream)
@@ -124,8 +121,8 @@ static int spitz_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -144,25 +141,25 @@ static int spitz_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
        /* set the I2S system clock as input (unused) */
-       ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -250,7 +247,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
 };
 
 /* Spitz machine audio_map */
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
 
        /* headphone connected to LOUT1, ROUT1 */
        {"Headphone Jack", NULL, "LOUT1"},
@@ -269,8 +266,6 @@ static const char *audio_map[][3] = {
 
        /* line is connected to input 1 - no bias */
        {"LINPUT1", NULL, "Line Jack"},
-
-       {NULL, NULL, NULL},
 };
 
 static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
@@ -296,13 +291,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
        int i, err;
 
        /* NC codec pins */
-       snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0);
-       snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0);
-       snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0);
-       snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0);
-       snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0);
-       snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
-       snd_soc_dapm_set_endpoint(codec, "MONO", 0);
+       snd_soc_dapm_disable_pin(codec, "RINPUT1");
+       snd_soc_dapm_disable_pin(codec, "LINPUT2");
+       snd_soc_dapm_disable_pin(codec, "RINPUT2");
+       snd_soc_dapm_disable_pin(codec, "LINPUT3");
+       snd_soc_dapm_disable_pin(codec, "RINPUT3");
+       snd_soc_dapm_disable_pin(codec, "OUT3");
+       snd_soc_dapm_disable_pin(codec, "MONO");
 
        /* Add spitz specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
@@ -313,15 +308,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
        }
 
        /* Add spitz specific widgets */
-       for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+                                 ARRAY_SIZE(wm8750_dapm_widgets));
 
-       /* Set up spitz specific audio path audio_map */
-       for (i = 0; audio_map[i][0] != NULL; i++)
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
+       /* Set up spitz specific audio paths */
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
        return 0;
 }
 
index 7346d7e5d066e71b84669f0fe6c054e77b003ca1..b6edb61a3a30f8591e89944d002fb7eff1c253ac 100644 (file)
@@ -12,9 +12,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    30th Nov 2005   Initial version.
- *
  * GPIO's
  *  1 - Jack Insertion
  *  5 - Hookswitch (headset answer/hang up switch)
@@ -55,29 +52,31 @@ static int tosa_spk_func;
 
 static void tosa_ext_control(struct snd_soc_codec *codec)
 {
-       int spk = 0, mic_int = 0, hp = 0, hs = 0;
-
        /* set up jack connection */
        switch (tosa_jack_func) {
        case TOSA_HP:
-               hp = 1;
+               snd_soc_dapm_disable_pin(codec, "Mic (Internal)");
+               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
                break;
        case TOSA_MIC_INT:
-               mic_int = 1;
+               snd_soc_dapm_enable_pin(codec, "Mic (Internal)");
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(codec, "Headset Jack");
                break;
        case TOSA_HEADSET:
-               hs = 1;
+               snd_soc_dapm_disable_pin(codec, "Mic (Internal)");
+               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_enable_pin(codec, "Headset Jack");
                break;
        }
 
        if (tosa_spk_func == TOSA_SPK_ON)
-               spk = 1;
+               snd_soc_dapm_enable_pin(codec, "Speaker");
+       else
+               snd_soc_dapm_disable_pin(codec, "Speaker");
 
-       snd_soc_dapm_set_endpoint(codec, "Speaker", spk);
-       snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int);
-       snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
-       snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 }
 
 static int tosa_startup(struct snd_pcm_substream *substream)
@@ -154,7 +153,7 @@ SND_SOC_DAPM_SPK("Speaker", NULL),
 };
 
 /* tosa audio map */
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
 
        /* headphone connected to HPOUTL, HPOUTR */
        {"Headphone Jack", NULL, "HPOUTL"},
@@ -173,8 +172,6 @@ static const char *audio_map[][3] = {
        {"Headset Jack", NULL, "HPOUTR"},
        {"LINEINR", NULL, "Mic Bias"},
        {"Mic Bias", NULL, "Headset Jack"},
-
-       {NULL, NULL, NULL},
 };
 
 static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
@@ -196,8 +193,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
-       snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
-       snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0);
+       snd_soc_dapm_disable_pin(codec, "OUT3");
+       snd_soc_dapm_disable_pin(codec, "MONOOUT");
 
        /* add tosa specific controls */
        for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
@@ -208,17 +205,13 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
        }
 
        /* add tosa specific widgets */
-       for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) {
-               snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]);
-       }
+       snd_soc_dapm_new_controls(codec, tosa_dapm_widgets,
+                                 ARRAY_SIZE(tosa_dapm_widgets));
 
        /* set up tosa specific audio path audio_map */
-       for (i = 0; audio_map[i][0] != NULL; i++) {
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
-       }
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
        return 0;
 }
 
index 1f6dbfc4caa85352412ba297e8094860e968fe00..b9f2353effebfba49cf5010c10bcf5b2794781c6 100644 (file)
@@ -1,7 +1,6 @@
 config SND_S3C24XX_SOC
        tristate "SoC Audio for the Samsung S3C24XX chips"
-       depends on ARCH_S3C2410 && SND_SOC
-       select SND_PCM
+       depends on ARCH_S3C2410
        help
          Say Y or M if you want to add support for codecs attached to
          the S3C24XX AC97, I2S or SSP interface. You will also need
@@ -16,7 +15,6 @@ config SND_S3C2412_SOC_I2S
 config SND_S3C2443_SOC_AC97
        tristate
        select AC97_BUS
-       select SND_AC97_CODEC
        select SND_SOC_AC97_BUS
        
 config SND_S3C24XX_SOC_NEO1973_WM8753
index 0e9d1c5f24840dab0d640d6f733aba13237742a2..4d7a9aa15f1a8cc20f41d390f5a0f87bcb35dcaf 100644 (file)
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    20th Jan 2007   Initial version.
- *    05th Feb 2007   Rename all to Neo1973
- *
  */
 
 #include <linux/module.h>
@@ -26,6 +22,7 @@
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/tlv.h>
 
 #include <asm/mach-types.h>
 #include <asm/hardware/scoop.h>
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
 
+/* Debugging stuff */
+#define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0
+#if S3C24XX_SOC_NEO1973_WM8753_DEBUG
+#define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x)
+#else
+#define DBG(x...)
+#endif
+
 /* define the scenarios */
 #define NEO_AUDIO_OFF                  0
 #define NEO_GSM_CALL_AUDIO_HANDSET     1
@@ -61,12 +66,14 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        unsigned int pll_out = 0, bclk = 0;
        int ret = 0;
        unsigned long iis_clkrate;
 
+       DBG("Entered %s\n", __func__);
+
        iis_clkrate = s3c24xx_i2s_get_clockrate();
 
        switch (params_rate(params)) {
@@ -101,44 +108,44 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai,
+       ret = snd_soc_dai_set_fmt(codec_dai,
                SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
-       ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+       ret = snd_soc_dai_set_fmt(cpu_dai,
                SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
        /* set MCLK division for sample rate */
-       ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
                S3C2410_IISMOD_32FS);
        if (ret < 0)
                return ret;
 
        /* set codec BCLK division for sample rate */
-       ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
        if (ret < 0)
                return ret;
 
        /* set prescaler division for sample rate */
-       ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
                S3C24XX_PRESCALE(4, 4));
        if (ret < 0)
                return ret;
 
        /* codec PLL input is PCLK/4 */
-       ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1,
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1,
                iis_clkrate / 4, pll_out);
        if (ret < 0)
                return ret;
@@ -149,10 +156,12 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
 static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+
+       DBG("Entered %s\n", __func__);
 
        /* disable the PLL */
-       return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
 }
 
 /*
@@ -167,11 +176,13 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
        unsigned int pcmdiv = 0;
        int ret = 0;
        unsigned long iis_clkrate;
 
+       DBG("Entered %s\n", __func__);
+
        iis_clkrate = s3c24xx_i2s_get_clockrate();
 
        if (params_rate(params) != 8000)
@@ -183,24 +194,24 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 
        /* todo: gg check mode (DSP_B) against CSR datasheet */
        /* set codec DAI configuration */
-       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
        /* set codec PCM division for sample rate */
-       ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
        if (ret < 0)
                return ret;
 
        /* configue and enable PLL for 12.288MHz output */
-       ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2,
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2,
                iis_clkrate / 4, 12288000);
        if (ret < 0)
                return ret;
@@ -211,10 +222,12 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+
+       DBG("Entered %s\n", __func__);
 
        /* disable the PLL */
-       return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
 }
 
 static struct snd_soc_ops neo1973_voice_ops = {
@@ -233,79 +246,81 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
 
 static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
 {
+       DBG("Entered %s\n", __func__);
+
        switch (neo1973_scenario) {
        case NEO_AUDIO_OFF:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_disable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        case NEO_GSM_CALL_AUDIO_HANDSET:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     1);
+               snd_soc_dapm_enable_pin(codec, "Audio Out");
+               snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_enable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_enable_pin(codec, "Call Mic");
                break;
        case NEO_GSM_CALL_AUDIO_HEADSET:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  1);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_enable_pin(codec, "Audio Out");
+               snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_enable_pin(codec, "GSM Line In");
+               snd_soc_dapm_enable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        case NEO_GSM_CALL_AUDIO_BLUETOOTH:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_disable_pin(codec, "Audio Out");
+               snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_enable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        case NEO_STEREO_TO_SPEAKERS:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_enable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        case NEO_STEREO_TO_HEADPHONES:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_enable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        case NEO_CAPTURE_HANDSET:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     1);
+               snd_soc_dapm_disable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_enable_pin(codec, "Call Mic");
                break;
        case NEO_CAPTURE_HEADSET:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  1);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_disable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_enable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        case NEO_CAPTURE_BLUETOOTH:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_disable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
                break;
        default:
-               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
-               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
-               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
-               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               snd_soc_dapm_disable_pin(codec, "Audio Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
+               snd_soc_dapm_disable_pin(codec, "GSM Line In");
+               snd_soc_dapm_disable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(codec, "Call Mic");
        }
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
 
        return 0;
 }
@@ -315,6 +330,8 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 
+       DBG("Entered %s\n", __func__);
+
        if (neo1973_scenario == ucontrol->value.integer.value[0])
                return 0;
 
@@ -327,6 +344,8 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
 
 static void lm4857_write_regs(void)
 {
+       DBG("Entered %s\n", __func__);
+
        if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
                printk(KERN_ERR "lm4857: i2c write failed\n");
 }
@@ -338,6 +357,8 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
        int shift = (kcontrol->private_value >> 8) & 0x0F;
        int mask = (kcontrol->private_value >> 16) & 0xFF;
 
+       DBG("Entered %s\n", __func__);
+
        ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
        return 0;
 }
@@ -364,6 +385,8 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
 {
        u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
 
+       DBG("Entered %s\n", __func__);
+
        if (value)
                value -= 5;
 
@@ -376,6 +399,8 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
 {
        u8 value = ucontrol->value.integer.value[0];
 
+       DBG("Entered %s\n", __func__);
+
        if (value)
                value += 5;
 
@@ -397,8 +422,7 @@ static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
 };
 
 
-/* example machine audio_mapnections */
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route dapm_routes[] = {
 
        /* Connections to the lm4857 amp */
        {"Audio Out", NULL, "LOUT1"},
@@ -421,8 +445,6 @@ static const char *audio_map[][3] = {
 
        /* Connect the ALC pins */
        {"ACIN", NULL, "ACOP"},
-
-       {NULL, NULL, NULL},
 };
 
 static const char *lm4857_mode[] = {
@@ -453,13 +475,16 @@ static const struct soc_enum neo_scenario_enum[] = {
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
 };
 
+static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
+
 static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
-       SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
-               lm4857_get_reg, lm4857_set_reg),
-       SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
-               lm4857_get_reg, lm4857_set_reg),
-       SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
-               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg, stereo_tlv),
+       SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg, stereo_tlv),
+       SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg, mono_tlv),
        SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
                lm4857_get_mode, lm4857_set_mode),
        SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
@@ -483,21 +508,23 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
 {
        int i, err;
 
+       DBG("Entered %s\n", __func__);
+
        /* set up NC codec pins */
-       snd_soc_dapm_set_endpoint(codec, "LOUT2", 0);
-       snd_soc_dapm_set_endpoint(codec, "ROUT2", 0);
-       snd_soc_dapm_set_endpoint(codec, "OUT3",  0);
-       snd_soc_dapm_set_endpoint(codec, "OUT4",  0);
-       snd_soc_dapm_set_endpoint(codec, "LINE1", 0);
-       snd_soc_dapm_set_endpoint(codec, "LINE2", 0);
+       snd_soc_dapm_disable_pin(codec, "LOUT2");
+       snd_soc_dapm_disable_pin(codec, "ROUT2");
+       snd_soc_dapm_disable_pin(codec, "OUT3");
+       snd_soc_dapm_disable_pin(codec, "OUT4");
+       snd_soc_dapm_disable_pin(codec, "LINE1");
+       snd_soc_dapm_disable_pin(codec, "LINE2");
 
 
        /* set endpoints to default mode */
        set_scenario_endpoints(codec, NEO_AUDIO_OFF);
 
        /* Add neo1973 specific widgets */
-       for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
+       snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
+                                 ARRAY_SIZE(wm8753_dapm_widgets));
 
        /* add neo1973 specific controls */
        for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
@@ -508,20 +535,18 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
                        return err;
        }
 
-       /* set up neo1973 specific audio path audio_mapnects */
-       for (i = 0; audio_map[i][0] != NULL; i++) {
-               snd_soc_dapm_connect_input(codec, audio_map[i][0],
-                       audio_map[i][1], audio_map[i][2]);
-       }
+       /* set up neo1973 specific audio routes */
+       err = snd_soc_dapm_add_routes(codec, dapm_routes,
+                                     ARRAY_SIZE(dapm_routes));
 
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
        return 0;
 }
 
 /*
  * BT Codec DAI
  */
-static struct snd_soc_cpu_dai bt_dai = {
+static struct snd_soc_dai bt_dai = {
        .name = "Bluetooth",
        .id = 0,
        .type = SND_SOC_DAI_PCM,
@@ -583,6 +608,8 @@ static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
 {
        int ret;
 
+       DBG("Entered %s\n", __func__);
+
        client_template.adapter = adap;
        client_template.addr = addr;
 
@@ -606,6 +633,8 @@ exit_err:
 
 static int lm4857_i2c_detach(struct i2c_client *client)
 {
+       DBG("Entered %s\n", __func__);
+
        i2c_detach_client(client);
        kfree(client);
        return 0;
@@ -613,6 +642,8 @@ static int lm4857_i2c_detach(struct i2c_client *client)
 
 static int lm4857_i2c_attach(struct i2c_adapter *adap)
 {
+       DBG("Entered %s\n", __func__);
+
        return i2c_probe(adap, &addr_data, lm4857_amp_probe);
 }
 
@@ -620,6 +651,8 @@ static u8 lm4857_state;
 
 static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
 {
+       DBG("Entered %s\n", __func__);
+
        dev_dbg(&dev->dev, "lm4857_suspend\n");
        lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
        if (lm4857_state) {
@@ -631,6 +664,8 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
 
 static int lm4857_resume(struct i2c_client *dev)
 {
+       DBG("Entered %s\n", __func__);
+
        if (lm4857_state) {
                lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
                lm4857_write_regs();
@@ -640,6 +675,8 @@ static int lm4857_resume(struct i2c_client *dev)
 
 static void lm4857_shutdown(struct i2c_client *dev)
 {
+       DBG("Entered %s\n", __func__);
+
        dev_dbg(&dev->dev, "lm4857_shutdown\n");
        lm4857_regs[LM4857_CTRL] &= 0xf0;
        lm4857_write_regs();
@@ -671,6 +708,8 @@ static int __init neo1973_init(void)
 {
        int ret;
 
+       DBG("Entered %s\n", __func__);
+
        neo1973_snd_device = platform_device_alloc("soc-audio", -1);
        if (!neo1973_snd_device)
                return -ENOMEM;
@@ -691,6 +730,8 @@ static int __init neo1973_init(void)
 
 static void __exit neo1973_exit(void)
 {
+       DBG("Entered %s\n", __func__);
+
        i2c_del_driver(&lm4857_i2c_driver);
        platform_device_unregister(neo1973_snd_device);
 }
index c4a46dd589b3b1565f6c3d2e450465a3a4c6744b..ee4676ed1283c80729a0b1314f6730c82b2ab1b1 100644 (file)
@@ -295,7 +295,7 @@ static inline int s3c2412_snd_is_clkmaster(void)
 /*
  * Set S3C2412 I2S DAI format
  */
-static int s3c2412_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                               unsigned int fmt)
 {
        u32 iismod;
@@ -500,7 +500,7 @@ EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
 /*
  * Set S3C2412 Clock source
  */
-static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                                  int clk_id, unsigned int freq, int dir)
 {
        u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
@@ -528,7 +528,7 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
 /*
  * Set S3C2412 Clock dividers
  */
-static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                  int div_id, int div)
 {
        struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
@@ -601,7 +601,8 @@ struct clk *s3c2412_get_iisclk(void)
 EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
 
 
-static int s3c2412_i2s_probe(struct platform_device *pdev)
+static int s3c2412_i2s_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
 {
        DBG("Entered %s\n", __func__);
 
@@ -647,7 +648,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 static int s3c2412_i2s_suspend(struct platform_device *dev,
-                             struct snd_soc_cpu_dai *dai)
+                             struct snd_soc_dai *dai)
 {
        struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
        u32 iismod;
@@ -675,7 +676,7 @@ static int s3c2412_i2s_suspend(struct platform_device *dev,
 }
 
 static int s3c2412_i2s_resume(struct platform_device *pdev,
-                             struct snd_soc_cpu_dai *dai)
+                             struct snd_soc_dai *dai)
 {
        struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
 
@@ -707,7 +708,7 @@ static int s3c2412_i2s_resume(struct platform_device *pdev,
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
-struct snd_soc_cpu_dai s3c2412_i2s_dai = {
+struct snd_soc_dai s3c2412_i2s_dai = {
        .name   = "s3c2412-i2s",
        .id     = 0,
        .type   = SND_SOC_DAI_I2S,
index 27f48e1ffa8610feb8e1d02740bd31bd607f59e9..aac08a25e541df2dc2cb6e0c0ebba094029105c7 100644 (file)
@@ -24,7 +24,7 @@
 
 extern struct clk *s3c2412_get_iisclk(void);
 
-extern struct snd_soc_cpu_dai s3c2412_i2s_dai;
+extern struct snd_soc_dai s3c2412_i2s_dai;
 
 struct s3c2412_rate_calc {
        unsigned int    clk_div;        /* for prescaler */
index e81d9a6c83dac829f356d12d52c3539418f2aea8..783349b7fedec91aec58fd30d1f8838cd026cc04 100644 (file)
@@ -10,9 +10,6 @@
  *  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.
- *
- *  Revision history
- *     21st Mar 2007   Initial Version
  */
 
 #include <linux/init.h>
@@ -212,7 +209,8 @@ static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
        .dma_size       = 4,
 };
 
-static int s3c2443_ac97_probe(struct platform_device *pdev)
+static int s3c2443_ac97_probe(struct platform_device *pdev,
+                             struct snd_soc_dai *dai)
 {
        int ret;
        u32 ac_glbctrl;
@@ -263,7 +261,8 @@ static int s3c2443_ac97_probe(struct platform_device *pdev)
        return ret;
 }
 
-static void s3c2443_ac97_remove(struct platform_device *pdev)
+static void s3c2443_ac97_remove(struct platform_device *pdev,
+                               struct snd_soc_dai *dai)
 {
        free_irq(IRQ_S3C244x_AC97, NULL);
        clk_disable(s3c24xx_ac97.ac97_clk);
@@ -275,7 +274,7 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
@@ -317,7 +316,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
@@ -353,7 +352,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
-struct snd_soc_cpu_dai s3c2443_ac97_dai[] = {
+struct snd_soc_dai s3c2443_ac97_dai[] = {
 {
        .name = "s3c2443-ac97",
        .id = 0,
index bf03e8ed16c30a8b22b4cf5d37e151b12ffc6a00..a96dcadf28b4a0726cf91240d8b4440888cdfb6d 100644 (file)
@@ -26,6 +26,6 @@
 #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97
 #endif
 
-extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
+extern struct snd_soc_dai s3c2443_ac97_dai[];
 
 #endif /*S3C24XXAC97_H_*/
index 1ed6afd454591ac9c5cab7b82b13b4105681826e..397524282b57f3ce865255d5bf7e3899df718be0 100644 (file)
  *  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.
- *
- *
- *  Revision history
- *    11th Dec 2006   Merged with Simtec driver
- *    10th Nov 2006   Initial version.
  */
 
 #include <linux/init.h>
@@ -180,7 +175,7 @@ static void s3c24xx_snd_rxctrl(int on)
 static int s3c24xx_snd_lrsync(void)
 {
        u32 iiscon;
-       unsigned long timeout = jiffies + msecs_to_jiffies(5);
+       int timeout = 50; /* 5ms */
 
        DBG("Entered %s\n", __func__);
 
@@ -189,8 +184,9 @@ static int s3c24xx_snd_lrsync(void)
                if (iiscon & S3C2410_IISCON_LRINDEX)
                        break;
 
-               if (time_after(jiffies, timeout))
+               if (!timeout--)
                        return -ETIMEDOUT;
+               udelay(100);
        }
 
        return 0;
@@ -209,7 +205,7 @@ static inline int s3c24xx_snd_is_clkmaster(void)
 /*
  * Set S3C24xx I2S DAI format
  */
-static int s3c24xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
        u32 iismod;
@@ -317,7 +313,7 @@ exit_err:
 /*
  * Set S3C24xx Clock source
  */
-static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
        int clk_id, unsigned int freq, int dir)
 {
        u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -343,7 +339,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
 /*
  * Set S3C24xx Clock dividers
  */
-static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
        int div_id, int div)
 {
        u32 reg;
@@ -381,7 +377,8 @@ u32 s3c24xx_i2s_get_clockrate(void)
 }
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 
-static int s3c24xx_i2s_probe(struct platform_device *pdev)
+static int s3c24xx_i2s_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
 {
        DBG("Entered %s\n", __func__);
 
@@ -414,7 +411,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 static int s3c24xx_i2s_suspend(struct platform_device *pdev,
-               struct snd_soc_cpu_dai *cpu_dai)
+               struct snd_soc_dai *cpu_dai)
 {
        DBG("Entered %s\n", __func__);
 
@@ -429,7 +426,7 @@ static int s3c24xx_i2s_suspend(struct platform_device *pdev,
 }
 
 static int s3c24xx_i2s_resume(struct platform_device *pdev,
-               struct snd_soc_cpu_dai *cpu_dai)
+               struct snd_soc_dai *cpu_dai)
 {
        DBG("Entered %s\n", __func__);
        clk_enable(s3c24xx_i2s.iis_clk);
@@ -452,7 +449,7 @@ static int s3c24xx_i2s_resume(struct platform_device *pdev,
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
-struct snd_soc_cpu_dai s3c24xx_i2s_dai = {
+struct snd_soc_dai s3c24xx_i2s_dai = {
        .name = "s3c24xx-i2s",
        .id = 0,
        .type = SND_SOC_DAI_I2S,
index 537b4ecce8a39e46847c442839d038282e4b8532..726d91cf4e1cfcbf624facdf7c0a697962bab190 100644 (file)
@@ -32,6 +32,6 @@
 
 u32 s3c24xx_i2s_get_clockrate(void);
 
-extern struct snd_soc_cpu_dai s3c24xx_i2s_dai;
+extern struct snd_soc_dai s3c24xx_i2s_dai;
 
 #endif /*S3C24XXI2S_H_*/
index 7806ae614617ca13f2c8c3325cf2daa800820f35..cef79b34dc6fc22e8789adef0e9c4be8e6ae8bbc 100644 (file)
  *  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.
- *
- *  Revision history
- *    11th Dec 2006   Merged with Simtec driver
- *    10th Nov 2006   Initial version.
  */
 
 #include <linux/module.h>
@@ -433,7 +429,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK;
 
 static int s3c24xx_pcm_new(struct snd_card *card,
-       struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
+       struct snd_soc_dai *dai, struct snd_pcm *pcm)
 {
        int ret = 0;
 
index b4a56302b9ab091203427333c2174c35d4341ca2..8515d6ff03f2c50c5220f8a39cf9ec7a0389693d 100644 (file)
@@ -10,9 +10,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    8th Mar 2007   Initial version.
- *
  */
 
 #include <linux/module.h>
index 4c1e013381c9dbc1f7a70a38527f302334db1d34..54bd604012af6ce2d96fab4a111f7ba519292b2c 100644 (file)
@@ -3,7 +3,7 @@ menu "SoC Audio support for SuperH"
 
 config SND_SOC_PCM_SH7760
        tristate "SoC Audio support for Renesas SH7760"
-       depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG
+       depends on CPU_SUBTYPE_SH7760 && SH_DMABRG
        help
          Enable this option for SH7760 AC97/I2S audio support.
 
@@ -13,10 +13,9 @@ config SND_SOC_PCM_SH7760
 ##
 
 config SND_SOC_SH4_HAC
+       tristate
        select AC97_BUS
        select SND_SOC_AC97_BUS
-       select SND_AC97_CODEC
-       tristate
 
 config SND_SOC_SH4_SSI
        tristate
index 7a3ce80d6727dbe2daea6fa691ef0daff4974481..9faa12622d09c07895c48cdf5d96ff6cfd47e38e 100644 (file)
@@ -326,7 +326,7 @@ static void camelot_pcm_free(struct snd_pcm *pcm)
 }
 
 static int camelot_pcm_new(struct snd_card *card,
-                          struct snd_soc_codec_dai *dai,
+                          struct snd_soc_dai *dai,
                           struct snd_pcm *pcm)
 {
        /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
index b7b676b3d6715c38fd6196ce10162d245daca36d..df7bc345c3205cc0ae069322f6243e1027b71492 100644 (file)
@@ -266,7 +266,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream,
 #define AC97_FMTS      \
        SNDRV_PCM_FMTBIT_S16_LE
 
-struct snd_soc_cpu_dai sh4_hac_dai[] = {
+struct snd_soc_dai sh4_hac_dai[] = {
 {
        .name                   = "HAC0",
        .id                     = 0,
index 2f91de84c5c762a2896c14230140c90b216d39a9..92bfaf4774a7d05fec84bf270539c8be09a6b05d 100644 (file)
 #define IPSEL 0xFE400034
 
 /* platform specific structs can be declared here */
-extern struct snd_soc_cpu_dai sh4_hac_dai[2];
+extern struct snd_soc_dai sh4_hac_dai[2];
 extern struct snd_soc_platform sh7760_soc_platform;
 
 static int machine_init(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_sync_endpoints(codec);
+       snd_soc_dapm_sync(codec);
        return 0;
 }
 
index 3388bc3d62d10fbef92a56c148ea4259ae2a6654..55c3464163ab45b50b7c359ef50b138c994bfcd1 100644 (file)
@@ -208,7 +208,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
+static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
                          unsigned int freq, int dir)
 {
        struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
@@ -222,7 +222,7 @@ static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
  * This divider is used to generate the SSI_SCK (I2S bitclock) from the
  * clock at the HAC_BIT_CLK ("oversampling clock") pin.
  */
-static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div)
+static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div)
 {
        struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
        unsigned long ssicr;
@@ -245,7 +245,7 @@ static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div)
        return 0;
 }
 
-static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
+static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
        unsigned long ssicr = SSIREG(SSICR);
@@ -332,7 +332,7 @@ static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
         SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
 
-struct snd_soc_cpu_dai sh4_ssi_dai[] = {
+struct snd_soc_dai sh4_ssi_dai[] = {
 {
        .name                   = "SSI0",
        .id                     = 0,
index e148db940cfc77ecb4521df7191909f00e672761..83f1190293a8287c2a516a81a07575dc7f4933c7 100644 (file)
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    12th Aug 2005   Initial version.
- *    25th Oct 2005   Working Codec, Interface and Platform registration.
- *
  *  TODO:
  *   o Add hw rules to enforce rates, etc.
  *   o More testing with other codecs/machines.
@@ -112,9 +108,9 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
 }
 #endif
 
-static inline const charget_dai_name(int type)
+static inline const char *get_dai_name(int type)
 {
-       switch(type) {
+       switch (type) {
        case SND_SOC_DAI_AC97_BUS:
        case SND_SOC_DAI_AC97:
                return "AC97";
@@ -138,8 +134,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
@@ -182,9 +178,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        /* Check that the codec and cpu DAI's are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                runtime->hw.rate_min =
-                       max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min);
+                       max(codec_dai->playback.rate_min,
+                           cpu_dai->playback.rate_min);
                runtime->hw.rate_max =
-                       min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max);
+                       min(codec_dai->playback.rate_max,
+                           cpu_dai->playback.rate_max);
                runtime->hw.channels_min =
                        max(codec_dai->playback.channels_min,
                                cpu_dai->playback.channels_min);
@@ -197,9 +195,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                        codec_dai->playback.rates & cpu_dai->playback.rates;
        } else {
                runtime->hw.rate_min =
-                       max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min);
+                       max(codec_dai->capture.rate_min,
+                           cpu_dai->capture.rate_min);
                runtime->hw.rate_max =
-                       min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max);
+                       min(codec_dai->capture.rate_max,
+                           cpu_dai->capture.rate_max);
                runtime->hw.channels_min =
                        max(codec_dai->capture.channels_min,
                                cpu_dai->capture.channels_min);
@@ -229,7 +229,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                goto machine_err;
        }
 
-       dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name);
+       dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
        dbg("asoc: rate mask 0x%x\n", runtime->hw.rates);
        dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
                runtime->hw.channels_max);
@@ -272,11 +272,11 @@ static void close_delayed_work(struct work_struct *work)
        struct snd_soc_device *socdev =
                container_of(work, struct snd_soc_device, delayed_work.work);
        struct snd_soc_codec *codec = socdev->codec;
-       struct snd_soc_codec_dai *codec_dai;
+       struct snd_soc_dai *codec_dai;
        int i;
 
        mutex_lock(&pcm_mutex);
-       for(i = 0; i < codec->num_dai; i++) {
+       for (i = 0; i < codec->num_dai; i++) {
                codec_dai = &codec->dai[i];
 
                dbg("pop wq checking: %s status: %s waiting: %s\n",
@@ -287,12 +287,12 @@ static void close_delayed_work(struct work_struct *work)
                /* are we waiting on this codec DAI stream */
                if (codec_dai->pop_wait == 1) {
 
-                       /* power down the codec to D1 if no longer active */
+                       /* Reduce power if no longer active */
                        if (codec->active == 0) {
                                dbg("pop wq D1 %s %s\n", codec->name,
                                        codec_dai->playback.stream_name);
-                               snd_soc_dapm_device_event(socdev,
-                                       SNDRV_CTL_POWER_D1);
+                               snd_soc_dapm_set_bias_level(socdev,
+                                       SND_SOC_BIAS_PREPARE);
                        }
 
                        codec_dai->pop_wait = 0;
@@ -300,12 +300,12 @@ static void close_delayed_work(struct work_struct *work)
                                codec_dai->playback.stream_name,
                                SND_SOC_DAPM_STREAM_STOP);
 
-                       /* power down the codec power domain if no longer active */
+                       /* Fall into standby if no longer active */
                        if (codec->active == 0) {
                                dbg("pop wq D3 %s %s\n", codec->name,
                                        codec_dai->playback.stream_name);
-                               snd_soc_dapm_device_event(socdev,
-                                       SNDRV_CTL_POWER_D3hot);
+                               snd_soc_dapm_set_bias_level(socdev,
+                                       SND_SOC_BIAS_STANDBY);
                        }
                }
        }
@@ -323,8 +323,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
        struct snd_soc_codec *codec = socdev->codec;
 
        mutex_lock(&pcm_mutex);
@@ -365,8 +365,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
                        SND_SOC_DAPM_STREAM_STOP);
 
                if (codec->active == 0 && codec_dai->pop_wait == 0)
-                       snd_soc_dapm_device_event(socdev,
-                                               SNDRV_CTL_POWER_D3hot);
+                       snd_soc_dapm_set_bias_level(socdev,
+                                               SND_SOC_BIAS_STANDBY);
        }
 
        mutex_unlock(&pcm_mutex);
@@ -384,8 +384,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
        struct snd_soc_codec *codec = socdev->codec;
        int ret = 0;
 
@@ -434,14 +434,14 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                else {
                        codec_dai->pop_wait = 0;
                        cancel_delayed_work(&socdev->delayed_work);
-                       if (codec_dai->dai_ops.digital_mute)
-                               codec_dai->dai_ops.digital_mute(codec_dai, 0);
+                       snd_soc_dai_digital_mute(codec_dai, 0);
                }
        } else {
                /* no delayed work - do we need to power up codec */
-               if (codec->dapm_state != SNDRV_CTL_POWER_D0) {
+               if (codec->bias_level != SND_SOC_BIAS_ON) {
 
-                       snd_soc_dapm_device_event(socdev,  SNDRV_CTL_POWER_D1);
+                       snd_soc_dapm_set_bias_level(socdev,
+                                                   SND_SOC_BIAS_PREPARE);
 
                        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                                snd_soc_dapm_stream_event(codec,
@@ -452,9 +452,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                                        codec_dai->capture.stream_name,
                                        SND_SOC_DAPM_STREAM_START);
 
-                       snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0);
-                       if (codec_dai->dai_ops.digital_mute)
-                               codec_dai->dai_ops.digital_mute(codec_dai, 0);
+                       snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON);
+                       snd_soc_dai_digital_mute(codec_dai, 0);
 
                } else {
                        /* codec already powered - power on widgets */
@@ -466,8 +465,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                                snd_soc_dapm_stream_event(codec,
                                        codec_dai->capture.stream_name,
                                        SND_SOC_DAPM_STREAM_START);
-                       if (codec_dai->dai_ops.digital_mute)
-                               codec_dai->dai_ops.digital_mute(codec_dai, 0);
+
+                       snd_soc_dai_digital_mute(codec_dai, 0);
                }
        }
 
@@ -488,8 +487,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
@@ -514,7 +513,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        if (cpu_dai->ops.hw_params) {
                ret = cpu_dai->ops.hw_params(substream, params);
                if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't set interface %s hw params\n",
+                       printk(KERN_ERR "asoc: interface %s hw params failed\n",
                                cpu_dai->name);
                        goto interface_err;
                }
@@ -523,7 +522,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
        if (platform->pcm_ops->hw_params) {
                ret = platform->pcm_ops->hw_params(substream, params);
                if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't set platform %s hw params\n",
+                       printk(KERN_ERR "asoc: platform %s hw params failed\n",
                                platform->name);
                        goto platform_err;
                }
@@ -542,7 +541,7 @@ interface_err:
                codec_dai->ops.hw_free(substream);
 
 codec_err:
-       if(machine->ops && machine->ops->hw_free)
+       if (machine->ops && machine->ops->hw_free)
                machine->ops->hw_free(substream);
 
        mutex_unlock(&pcm_mutex);
@@ -558,15 +557,15 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
        struct snd_soc_codec *codec = socdev->codec;
 
        mutex_lock(&pcm_mutex);
 
        /* apply codec digital mute */
-       if (!codec->active && codec_dai->dai_ops.digital_mute)
-               codec_dai->dai_ops.digital_mute(codec_dai, 1);
+       if (!codec->active)
+               snd_soc_dai_digital_mute(codec_dai, 1);
 
        /* free any machine hw params */
        if (machine->ops && machine->ops->hw_free)
@@ -593,8 +592,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_dai_link *machine = rtd->dai;
        struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_codec_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
        int ret;
 
        if (codec_dai->ops.trigger) {
@@ -631,16 +630,26 @@ static struct snd_pcm_ops soc_pcm_ops = {
 /* powers down audio subsystem for suspend */
 static int soc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_machine *machine = socdev->machine;
-       struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_machine *machine = socdev->machine;
+       struct snd_soc_platform *platform = socdev->platform;
+       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
        struct snd_soc_codec *codec = socdev->codec;
        int i;
 
+       /* Due to the resume being scheduled into a workqueue we could
+       * suspend before that's finished - wait for it to complete.
+        */
+       snd_power_lock(codec->card);
+       snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
+       snd_power_unlock(codec->card);
+
+       /* we're going to block userspace touching us until resume completes */
+       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
+
        /* mute any active DAC's */
-       for(i = 0; i < machine->num_links; i++) {
-               struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+       for (i = 0; i < machine->num_links; i++) {
+               struct snd_soc_dai *dai = machine->dai_link[i].codec_dai;
                if (dai->dai_ops.digital_mute && dai->playback.active)
                        dai->dai_ops.digital_mute(dai, 1);
        }
@@ -652,8 +661,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        if (machine->suspend_pre)
                machine->suspend_pre(pdev, state);
 
-       for(i = 0; i < machine->num_links; i++) {
-               struct snd_soc_cpu_dai  *cpu_dai = machine->dai_link[i].cpu_dai;
+       for (i = 0; i < machine->num_links; i++) {
+               struct snd_soc_dai  *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97)
                        cpu_dai->suspend(pdev, cpu_dai);
                if (platform->suspend)
@@ -662,9 +671,9 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
 
        /* close any waiting streams and save state */
        run_delayed_work(&socdev->delayed_work);
-       codec->suspend_dapm_state = codec->dapm_state;
+       codec->suspend_bias_level = codec->bias_level;
 
-       for(i = 0; i < codec->num_dai; i++) {
+       for (i = 0; i < codec->num_dai; i++) {
                char *stream = codec->dai[i].playback.stream_name;
                if (stream != NULL)
                        snd_soc_dapm_stream_event(codec, stream,
@@ -678,8 +687,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        if (codec_dev->suspend)
                codec_dev->suspend(pdev, state);
 
-       for(i = 0; i < machine->num_links; i++) {
-               struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+       for (i = 0; i < machine->num_links; i++) {
+               struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97)
                        cpu_dai->suspend(pdev, cpu_dai);
        }
@@ -690,21 +699,32 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-/* powers up audio subsystem after a suspend */
-static int soc_resume(struct platform_device *pdev)
+/* deferred resume work, so resume can complete before we finished
+ * setting our codec back up, which can be very slow on I2C
+ */
+static void soc_resume_deferred(struct work_struct *work)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_machine *machine = socdev->machine;
-       struct snd_soc_platform *platform = socdev->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+       struct snd_soc_device *socdev = container_of(work,
+                                                    struct snd_soc_device,
+                                                    deferred_resume_work);
+       struct snd_soc_machine *machine = socdev->machine;
+       struct snd_soc_platform *platform = socdev->platform;
+       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
        struct snd_soc_codec *codec = socdev->codec;
+       struct platform_device *pdev = to_platform_device(socdev->dev);
        int i;
 
+       /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
+        * so userspace apps are blocked from touching us
+        */
+
+       dev_info(socdev->dev, "starting resume work\n");
+
        if (machine->resume_pre)
                machine->resume_pre(pdev);
 
-       for(i = 0; i < machine->num_links; i++) {
-               struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+       for (i = 0; i < machine->num_links; i++) {
+               struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97)
                        cpu_dai->resume(pdev, cpu_dai);
        }
@@ -712,8 +732,8 @@ static int soc_resume(struct platform_device *pdev)
        if (codec_dev->resume)
                codec_dev->resume(pdev);
 
-       for(i = 0; i < codec->num_dai; i++) {
-               charstream = codec->dai[i].playback.stream_name;
+       for (i = 0; i < codec->num_dai; i++) {
+               char *stream = codec->dai[i].playback.stream_name;
                if (stream != NULL)
                        snd_soc_dapm_stream_event(codec, stream,
                                SND_SOC_DAPM_STREAM_RESUME);
@@ -723,15 +743,15 @@ static int soc_resume(struct platform_device *pdev)
                                SND_SOC_DAPM_STREAM_RESUME);
        }
 
-       /* unmute any active DAC's */
-       for(i = 0; i < machine->num_links; i++) {
-               struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
+       /* unmute any active DACs */
+       for (i = 0; i < machine->num_links; i++) {
+               struct snd_soc_dai *dai = machine->dai_link[i].codec_dai;
                if (dai->dai_ops.digital_mute && dai->playback.active)
                        dai->dai_ops.digital_mute(dai, 0);
        }
 
-       for(i = 0; i < machine->num_links; i++) {
-               struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+       for (i = 0; i < machine->num_links; i++) {
+               struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97)
                        cpu_dai->resume(pdev, cpu_dai);
                if (platform->resume)
@@ -741,6 +761,22 @@ static int soc_resume(struct platform_device *pdev)
        if (machine->resume_post)
                machine->resume_post(pdev);
 
+       dev_info(socdev->dev, "resume work completed\n");
+
+       /* userspace can access us now we are back as we were before */
+       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
+}
+
+/* powers up audio subsystem after a suspend */
+static int soc_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       dev_info(socdev->dev, "scheduling resume work\n");
+
+       if (!schedule_work(&socdev->deferred_resume_work))
+               dev_err(socdev->dev, "work item may be lost\n");
+
        return 0;
 }
 
@@ -760,33 +796,38 @@ static int soc_probe(struct platform_device *pdev)
 
        if (machine->probe) {
                ret = machine->probe(pdev);
-               if(ret < 0)
+               if (ret < 0)
                        return ret;
        }
 
        for (i = 0; i < machine->num_links; i++) {
-               struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+               struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->probe) {
-                       ret = cpu_dai->probe(pdev);
-                       if(ret < 0)
+                       ret = cpu_dai->probe(pdev, cpu_dai);
+                       if (ret < 0)
                                goto cpu_dai_err;
                }
        }
 
        if (codec_dev->probe) {
                ret = codec_dev->probe(pdev);
-               if(ret < 0)
+               if (ret < 0)
                        goto cpu_dai_err;
        }
 
        if (platform->probe) {
                ret = platform->probe(pdev);
-               if(ret < 0)
+               if (ret < 0)
                        goto platform_err;
        }
 
        /* DAPM stream work */
        INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work);
+#ifdef CONFIG_PM
+       /* deferred resume work */
+       INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred);
+#endif
+
        return 0;
 
 platform_err:
@@ -795,9 +836,9 @@ platform_err:
 
 cpu_dai_err:
        for (i--; i >= 0; i--) {
-               struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+               struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->remove)
-                       cpu_dai->remove(pdev);
+                       cpu_dai->remove(pdev, cpu_dai);
        }
 
        if (machine->remove)
@@ -824,9 +865,9 @@ static int soc_remove(struct platform_device *pdev)
                codec_dev->remove(pdev);
 
        for (i = 0; i < machine->num_links; i++) {
-               struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
+               struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai;
                if (cpu_dai->remove)
-                       cpu_dai->remove(pdev);
+                       cpu_dai->remove(pdev, cpu_dai);
        }
 
        if (machine->remove)
@@ -852,8 +893,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        struct snd_soc_dai_link *dai_link, int num)
 {
        struct snd_soc_codec *codec = socdev->codec;
-       struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai;
-       struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai;
+       struct snd_soc_dai *codec_dai = dai_link->codec_dai;
+       struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
        struct snd_soc_pcm_runtime *rtd;
        struct snd_pcm *pcm;
        char new_name[64];
@@ -868,7 +909,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        codec_dai->codec = socdev->codec;
 
        /* check client and interface hw capabilities */
-       sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name,
+       sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name,
                get_dai_name(cpu_dai->type), num);
 
        if (codec_dai->playback.channels_min)
@@ -879,7 +920,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
                capture, &pcm);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
+               printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
+                       codec->name);
                kfree(rtd);
                return ret;
        }
@@ -928,8 +970,9 @@ static ssize_t codec_reg_show(struct device *dev,
                step = codec->reg_cache_step;
 
        count += sprintf(buf, "%s registers\n", codec->name);
-       for(i = 0; i < codec->reg_cache_size; i += step)
-               count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i));
+       for (i = 0; i < codec->reg_cache_size; i += step)
+               count += sprintf(buf + count, "%2x: %4x\n", i,
+                       codec->read(codec, i));
 
        return count;
 }
@@ -1072,7 +1115,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
        strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
 
        /* create the pcms */
-       for(i = 0; i < machine->num_links; i++) {
+       for (i = 0; i < machine->num_links; i++) {
                ret = soc_new_pcm(socdev, &machine->dai_link[i], i);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't create pcm %s\n",
@@ -1102,7 +1145,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
        struct snd_soc_machine *machine = socdev->machine;
        int ret = 0, i, ac97 = 0, err = 0;
 
-       for(i = 0; i < machine->num_links; i++) {
+       for (i = 0; i < machine->num_links; i++) {
                if (socdev->machine->dai_link[i].init) {
                        err = socdev->machine->dai_link[i].init(codec);
                        if (err < 0) {
@@ -1111,7 +1154,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
                                continue;
                        }
                }
-               if (socdev->machine->dai_link[i].codec_dai->type == 
+               if (socdev->machine->dai_link[i].codec_dai->type ==
                        SND_SOC_DAI_AC97_BUS)
                        ac97 = 1;
        }
@@ -1122,7 +1165,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
 
        ret = snd_card_register(codec->card);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n",
+               printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
                                codec->name);
                goto out;
        }
@@ -1146,7 +1189,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
 
        err = device_create_file(socdev->dev, &dev_attr_codec_reg);
        if (err < 0)
-               printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
+               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 
        mutex_unlock(&codec->mutex);
 
@@ -1166,13 +1209,13 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev)
 {
        struct snd_soc_codec *codec = socdev->codec;
 #ifdef CONFIG_SND_SOC_AC97_BUS
-       struct snd_soc_codec_dai *codec_dai;
+       struct snd_soc_dai *codec_dai;
        int i;
 #endif
 
        mutex_lock(&codec->mutex);
 #ifdef CONFIG_SND_SOC_AC97_BUS
-       for(i = 0; i < codec->num_dai; i++) {
+       for (i = 0; i < codec->num_dai; i++) {
                codec_dai = &codec->dai[i];
                if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) {
                        soc_ac97_dev_unregister(codec);
@@ -1282,7 +1325,8 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
        for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
                ;
        val = snd_soc_read(codec, e->reg);
-       ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+       ucontrol->value.enumerated.item[0]
+               = (val >> e->shift_l) & (bitmask - 1);
        if (e->shift_l != e->shift_r)
                ucontrol->value.enumerated.item[1] =
                        (val >> e->shift_r) & (bitmask - 1);
@@ -1576,7 +1620,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
        val = val << shift;
        val2 = val2 << shift;
 
-       if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0)
+       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       if (err < 0)
                return err;
 
        err = snd_soc_update_bits(codec, reg2, val_mask, val2);
@@ -1584,6 +1629,204 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
 
+/**
+ * snd_soc_info_volsw_s8 - signed mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a signed mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       int max = (signed char)((kcontrol->private_value >> 16) & 0xff);
+       int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = max-min;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8);
+
+/**
+ * snd_soc_get_volsw_s8 - signed mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a signed mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int reg = kcontrol->private_value & 0xff;
+       int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+       int val = snd_soc_read(codec, reg);
+
+       ucontrol->value.integer.value[0] =
+               ((signed char)(val & 0xff))-min;
+       ucontrol->value.integer.value[1] =
+               ((signed char)((val >> 8) & 0xff))-min;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8);
+
+/**
+ * snd_soc_put_volsw_sgn - signed mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a signed mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int reg = kcontrol->private_value & 0xff;
+       int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+       unsigned short val;
+
+       val = (ucontrol->value.integer.value[0]+min) & 0xff;
+       val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
+
+       return snd_soc_update_bits(codec, reg, 0xffff, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
+
+/**
+ * snd_soc_dai_set_sysclk - configure DAI system or master clock.
+ * @dai: DAI
+ * @clk_id: DAI specific clock ID
+ * @freq: new clock frequency in Hz
+ * @dir: new clock direction - input/output.
+ *
+ * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
+ */
+int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+       unsigned int freq, int dir)
+{
+       if (dai->dai_ops.set_sysclk)
+               return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
+
+/**
+ * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
+ * @dai: DAI
+ * @clk_id: DAI specific clock divider ID
+ * @div: new clock divisor.
+ *
+ * Configures the clock dividers. This is used to derive the best DAI bit and
+ * frame clocks from the system or master clock. It's best to set the DAI bit
+ * and frame clocks as low as possible to save system power.
+ */
+int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
+       int div_id, int div)
+{
+       if (dai->dai_ops.set_clkdiv)
+               return dai->dai_ops.set_clkdiv(dai, div_id, div);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
+
+/**
+ * snd_soc_dai_set_pll - configure DAI PLL.
+ * @dai: DAI
+ * @pll_id: DAI specific PLL ID
+ * @freq_in: PLL input clock frequency in Hz
+ * @freq_out: requested PLL output clock frequency in Hz
+ *
+ * Configures and enables PLL to generate output clock based on input clock.
+ */
+int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
+       int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       if (dai->dai_ops.set_pll)
+               return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
+
+/**
+ * snd_soc_dai_set_fmt - configure DAI hardware audio format.
+ * @dai: DAI
+ * @clk_id: DAI specific clock ID
+ * @fmt: SND_SOC_DAIFMT_ format value.
+ *
+ * Configures the DAI hardware format and clocking.
+ */
+int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       if (dai->dai_ops.set_fmt)
+               return dai->dai_ops.set_fmt(dai, fmt);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
+
+/**
+ * snd_soc_dai_set_tdm_slot - configure DAI TDM.
+ * @dai: DAI
+ * @mask: DAI specific mask representing used slots.
+ * @slots: Number of slots in use.
+ *
+ * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
+ * specific.
+ */
+int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
+       unsigned int mask, int slots)
+{
+       if (dai->dai_ops.set_sysclk)
+               return dai->dai_ops.set_tdm_slot(dai, mask, slots);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
+
+/**
+ * snd_soc_dai_set_tristate - configure DAI system or master clock.
+ * @dai: DAI
+ * @tristate: tristate enable
+ *
+ * Tristates the DAI so that others can use it.
+ */
+int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+       if (dai->dai_ops.set_sysclk)
+               return dai->dai_ops.set_tristate(dai, tristate);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
+
+/**
+ * snd_soc_dai_digital_mute - configure DAI system or master clock.
+ * @dai: DAI
+ * @mute: mute enable
+ *
+ * Mutes the DAI DAC.
+ */
+int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       if (dai->dai_ops.digital_mute)
+               return dai->dai_ops.digital_mute(dai, mute);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
+
 static int __devinit snd_soc_init(void)
 {
        printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION);
@@ -1592,7 +1835,7 @@ static int __devinit snd_soc_init(void)
 
 static void snd_soc_exit(void)
 {
-       platform_driver_unregister(&soc_driver);
+       platform_driver_unregister(&soc_driver);
 }
 
 module_init(snd_soc_init);
index af3326c635041da0c852ecc0ca11ea91212484f1..2c87061c2a6b4d7b9c35d7479d782462a0d8b3c1 100644 (file)
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  Revision history
- *    12th Aug 2005   Initial version.
- *    25th Oct 2005   Implemented path power domain.
- *    18th Dec 2005   Implemented machine and stream level power domain.
- *
  *  Features:
  *    o Changes power status of internal codec blocks depending on the
  *      dynamic configuration of codec internal audio paths and active
 #include <sound/initval.h>
 
 /* debug */
-#define DAPM_DEBUG 0
-#if DAPM_DEBUG
+#ifdef DEBUG
 #define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
-#define dbg(format, arg...) printk(format, ## arg)
 #else
 #define dump_dapm(codec, action)
-#define dbg(format, arg...)
-#endif
-
-#define POP_DEBUG 0
-#if POP_DEBUG
-#define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */
-#define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time))
-#define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME)
-#else
-#define pop_dbg(format, arg...)
-#define pop_wait(time)
 #endif
 
 /* dapm power sequences - make this per codec in the future */
@@ -85,6 +67,28 @@ static int dapm_status = 1;
 module_param(dapm_status, int, 0);
 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
 
+static unsigned int pop_time;
+
+static void pop_wait(void)
+{
+       if (pop_time)
+               schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
+}
+
+static void pop_dbg(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+
+       if (pop_time) {
+               vprintk(fmt, args);
+               pop_wait();
+       }
+
+       va_end(args);
+}
+
 /* create a new dapm widget */
 static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        const struct snd_soc_dapm_widget *_widget)
@@ -222,11 +226,12 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
        change = old != new;
        if (change) {
                pop_dbg("pop test %s : %s in %d ms\n", widget->name,
-                       widget->power ? "on" : "off", POP_TIME);
+                       widget->power ? "on" : "off", pop_time);
                snd_soc_write(codec, widget->reg, new);
-               pop_wait(POP_TIME);
+               pop_wait();
        }
-       dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change);
+       pr_debug("reg %x old %x new %x change %d\n", widget->reg,
+                old, new, change);
        return change;
 }
 
@@ -447,6 +452,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
        return con;
 }
 
+/*
+ * Handler for generic register modifier widget.
+ */
+int dapm_reg_event(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol, int event)
+{
+       unsigned int val;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               val = w->on_val;
+       else
+               val = w->off_val;
+
+       snd_soc_update_bits(w->codec, -(w->reg + 1),
+                           w->mask << w->shift, val << w->shift);
+
+       return 0;
+}
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -565,8 +589,8 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                        /* call any power change event handlers */
                        if (power_change) {
                                if (w->event) {
-                                       dbg("power %s event for %s flags %x\n",
-                                               w->power ? "on" : "off", w->name, w->event_flags);
+                                       pr_debug("power %s event for %s flags %x\n",
+                                                w->power ? "on" : "off", w->name, w->event_flags);
                                        if (power) {
                                                /* power up event */
                                                if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
@@ -608,7 +632,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        return ret;
 }
 
-#if DAPM_DEBUG
+#ifdef DEBUG
 static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
 {
        struct snd_soc_dapm_widget *w;
@@ -693,8 +717,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                        path->connect = 0; /* old connection must be powered down */
        }
 
-       if (found)
+       if (found) {
                dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+               dump_dapm(widget->codec, "mux power update");
+       }
 
        return 0;
 }
@@ -730,8 +756,10 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
                break;
        }
 
-       if (found)
+       if (found) {
                dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+               dump_dapm(widget->codec, "mixer power update");
+       }
 
        return 0;
 }
@@ -768,21 +796,18 @@ static ssize_t dapm_widget_show(struct device *dev,
                }
        }
 
-       switch(codec->dapm_state){
-       case SNDRV_CTL_POWER_D0:
-               state = "D0";
+       switch (codec->bias_level) {
+       case SND_SOC_BIAS_ON:
+               state = "On";
                break;
-       case SNDRV_CTL_POWER_D1:
-               state = "D1";
+       case SND_SOC_BIAS_PREPARE:
+               state = "Prepare";
                break;
-       case SNDRV_CTL_POWER_D2:
-               state = "D2";
+       case SND_SOC_BIAS_STANDBY:
+               state = "Standby";
                break;
-       case SNDRV_CTL_POWER_D3hot:
-               state = "D3hot";
-               break;
-       case SNDRV_CTL_POWER_D3cold:
-               state = "D3cold";
+       case SND_SOC_BIAS_OFF:
+               state = "Off";
                break;
        }
        count += sprintf(buf + count, "PM State: %s\n", state);
@@ -792,20 +817,51 @@ static ssize_t dapm_widget_show(struct device *dev,
 
 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
+/* pop/click delay times */
+static ssize_t dapm_pop_time_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", pop_time);
+}
+
+static ssize_t dapm_pop_time_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+
+{
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) >= 0)
+               pop_time = val;
+       else
+               printk(KERN_ERR "Unable to parse pop_time setting\n");
+
+       return count;
+}
+
+static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
+                  dapm_pop_time_store);
+
 int snd_soc_dapm_sys_add(struct device *dev)
 {
        int ret = 0;
 
-       if (dapm_status)
+       if (dapm_status) {
                ret = device_create_file(dev, &dev_attr_dapm_widget);
 
+               if (ret == 0)
+                       ret = device_create_file(dev, &dev_attr_dapm_pop_time);
+       }
+
        return ret;
 }
 
 static void snd_soc_dapm_sys_remove(struct device *dev)
 {
-       if (dapm_status)
+       if (dapm_status) {
+               device_remove_file(dev, &dev_attr_dapm_pop_time);
                device_remove_file(dev, &dev_attr_dapm_widget);
+       }
 }
 
 /* free all dapm widgets and resources */
@@ -826,8 +882,25 @@ static void dapm_free_widgets(struct snd_soc_codec *codec)
        }
 }
 
+static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
+       char *pin, int status)
+{
+       struct snd_soc_dapm_widget *w;
+
+       list_for_each_entry(w, &codec->dapm_widgets, list) {
+               if (!strcmp(w->name, pin)) {
+                       pr_debug("dapm: %s: pin %s\n", codec->name, pin);
+                       w->connected = status;
+                       return 0;
+               }
+       }
+
+       pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
+       return -EINVAL;
+}
+
 /**
- * snd_soc_dapm_sync_endpoints - scan and power dapm paths
+ * snd_soc_dapm_sync - scan and power dapm paths
  * @codec: audio codec
  *
  * Walks all dapm audio paths and powers widgets according to their
@@ -835,27 +908,16 @@ static void dapm_free_widgets(struct snd_soc_codec *codec)
  *
  * Returns 0 for success.
  */
-int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
+int snd_soc_dapm_sync(struct snd_soc_codec *codec)
 {
-       return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+       int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+       dump_dapm(codec, "sync");
+       return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
-/**
- * snd_soc_dapm_connect_input - connect dapm widgets
- * @codec: audio codec
- * @sink: name of target widget
- * @control: mixer control name
- * @source: name of source name
- *
- * Connects 2 dapm widgets together via a named audio path. The sink is
- * the widget receiving the audio signal, whilst the source is the sender
- * of the audio signal.
- *
- * Returns 0 for success else error.
- */
-int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
-       const char * control, const char *source)
+static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
+       const char *sink, const char *control, const char *source)
 {
        struct snd_soc_dapm_path *path;
        struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
@@ -957,8 +1019,63 @@ err:
        kfree(path);
        return ret;
 }
+
+/**
+ * snd_soc_dapm_connect_input - connect dapm widgets
+ * @codec: audio codec
+ * @sink: name of target widget
+ * @control: mixer control name
+ * @source: name of source name
+ *
+ * Connects 2 dapm widgets together via a named audio path. The sink is
+ * the widget receiving the audio signal, whilst the source is the sender
+ * of the audio signal.
+ *
+ * This function has been deprecated in favour of snd_soc_dapm_add_routes().
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
+       const char *control, const char *source)
+{
+       return snd_soc_dapm_add_route(codec, sink, control, source);
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
 
+/**
+ * snd_soc_dapm_add_routes - Add routes between DAPM widgets
+ * @codec: codec
+ * @route: audio routes
+ * @num: number of routes
+ *
+ * Connects 2 dapm widgets together via a named audio path. The sink is
+ * the widget receiving the audio signal, whilst the source is the sender
+ * of the audio signal.
+ *
+ * Returns 0 for success else error. On error all resources can be freed
+ * with a call to snd_soc_card_free().
+ */
+int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
+                           const struct snd_soc_dapm_route *route, int num)
+{
+       int i, ret;
+
+       for (i = 0; i < num; i++) {
+               ret = snd_soc_dapm_add_route(codec, route->sink,
+                                            route->control, route->source);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to add route %s->%s\n",
+                              route->source,
+                              route->sink);
+                       return ret;
+               }
+               route++;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
+
 /**
  * snd_soc_dapm_new_widgets - add new dapm widgets
  * @codec: audio codec
@@ -1233,6 +1350,33 @@ int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
 
+/**
+ * snd_soc_dapm_new_controls - create new dapm controls
+ * @codec: audio codec
+ * @widget: widget array
+ * @num: number of widgets
+ *
+ * Creates new DAPM controls based upon the templates.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
+       const struct snd_soc_dapm_widget *widget,
+       int num)
+{
+       int i, ret;
+
+       for (i = 0; i < num; i++) {
+               ret = snd_soc_dapm_new_control(codec, widget);
+               if (ret < 0)
+                       return ret;
+               widget++;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
+
+
 /**
  * snd_soc_dapm_stream_event - send a stream event to the dapm core
  * @codec: audio codec
@@ -1257,8 +1401,8 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
        {
                if (!w->sname)
                        continue;
-               dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
-                       stream, event);
+               pr_debug("widget %s\n %s stream %s event %d\n",
+                        w->name, w->sname, stream, event);
                if (strstr(w->sname, stream)) {
                        switch(event) {
                        case SND_SOC_DAPM_STREAM_START:
@@ -1294,53 +1438,81 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
 
 /**
- * snd_soc_dapm_device_event - send a device event to the dapm core
+ * snd_soc_dapm_set_bias_level - set the bias level for the system
  * @socdev: audio device
- * @event: device event
+ * @level: level to configure
  *
- * Sends a device event to the dapm core. The core then makes any
- * necessary machine or codec power changes..
+ * Configure the bias (power) levels for the SoC audio device.
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event)
+int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
+                               enum snd_soc_bias_level level)
 {
        struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_machine *machine = socdev->machine;
+       int ret = 0;
 
-       if (machine->dapm_event)
-               machine->dapm_event(machine, event);
-       if (codec->dapm_event)
-               codec->dapm_event(codec, event);
-       return 0;
+       if (machine->set_bias_level)
+               ret = machine->set_bias_level(machine, level);
+       if (ret == 0 && codec->set_bias_level)
+               ret = codec->set_bias_level(codec, level);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event);
 
 /**
- * snd_soc_dapm_set_endpoint - set audio endpoint status
+ * snd_soc_dapm_enable_pin - enable pin.
+ * @snd_soc_codec: SoC codec
+ * @pin: pin name
+ *
+ * Enables input/output pin and it's parents or children widgets iff there is
+ * a valid audio route and active audio stream.
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin)
+{
+       return snd_soc_dapm_set_pin(codec, pin, 1);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
+
+/**
+ * snd_soc_dapm_disable_pin - disable pin.
+ * @codec: SoC codec
+ * @pin: pin name
+ *
+ * Disables input/output pin and it's parents or children widgets.
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
+{
+       return snd_soc_dapm_set_pin(codec, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
+
+/**
+ * snd_soc_dapm_get_pin_status - get audio pin status
  * @codec: audio codec
- * @endpoint: audio signal endpoint (or start point)
- * @status: point status
+ * @pin: audio signal pin endpoint (or start point)
  *
- * Set audio endpoint status - connected or disconnected.
+ * Get audio pin status - connected or disconnected.
  *
- * Returns 0 for success else error.
+ * Returns 1 for connected otherwise 0.
  */
-int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
-       char *endpoint, int status)
+int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin)
 {
        struct snd_soc_dapm_widget *w;
 
        list_for_each_entry(w, &codec->dapm_widgets, list) {
-               if (!strcmp(w->name, endpoint)) {
-                       w->connected = status;
-                       return 0;
-               }
+               if (!strcmp(w->name, pin))
+                       return w->connected;
        }
 
-       return -ENODEV;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
 
 /**
  * snd_soc_dapm_free - free dapm resources
index 079e22af074c08cf45bdc0bc0559f327869dcce8..d75deba5617db05dc02407b6c669d61ee1695a5e 100644 (file)
@@ -1,11 +1,17 @@
 # ALSA Sparc drivers
 
-menu "ALSA Sparc devices"
-       depends on SND!=n && SPARC
+menuconfig SND_SPARC
+       bool "Sparc sound devices"
+       depends on SPARC
+       default y
+       help
+         Support for sound devices specific to Sun SPARC architectures.
+
+if SND_SPARC
 
 config SND_SUN_AMD7930
        tristate "Sun AMD7930"
-       depends on SBUS && SND
+       depends on SBUS
        select SND_PCM
        help
          Say Y here to include support for AMD7930 sound device on Sun.
@@ -15,7 +21,6 @@ config SND_SUN_AMD7930
 
 config SND_SUN_CS4231
        tristate "Sun CS4231"
-       depends on SND
        select SND_PCM
        help
          Say Y here to include support for CS4231 sound device on Sun.
@@ -25,7 +30,7 @@ config SND_SUN_CS4231
 
 config SND_SUN_DBRI
        tristate "Sun DBRI"
-       depends on SND && SBUS
+       depends on SBUS
        select SND_PCM
        help
          Say Y here to include support for DBRI sound device on Sun.
@@ -33,4 +38,4 @@ config SND_SUN_DBRI
          To compile this driver as a module, choose M here: the module
          will be called snd-sun-dbri.
 
-endmenu
+endif  # SND_SPARC
index 3d00e0797b11899042e5af98fa64a224ebc13597..ee2e1b4f35514dfa999dabcccfb689bf9ecd077d 100644 (file)
@@ -2490,7 +2490,7 @@ static void dbri_debug_read(struct snd_info_entry *entry,
 }
 #endif
 
-void __devinit snd_dbri_proc(struct snd_card *card)
+static void __devinit snd_dbri_proc(struct snd_card *card)
 {
        struct snd_dbri *dbri = card->private_data;
        struct snd_info_entry *entry;
index 0d08c29213c8ffa9db4ceea7195ba01e1c746053..e6485be2e6f7a70c1762041ca89e323eb5c5c3e4 100644 (file)
@@ -1,7 +1,13 @@
 #SPI drivers
 
-menu "SPI devices"
-       depends on SND != n
+menuconfig SND_SPI
+       bool "SPI sound devices"
+       depends on SPI
+       default y
+       help
+         Support for sound devices connected via the SPI bus.
+
+if SND_SPI
 
 config SND_AT73C213
        tristate "Atmel AT73C213 DAC driver"
@@ -28,4 +34,5 @@ config SND_AT73C213_TARGET_BITRATE
 
          Set to 48000 Hz by default.
 
-endmenu
+endif  # SND_SPI
+
index 9351b8a765b9c6de7f5069e2c3c6d09b0f54a50d..ffcdc8f4ef66de645e41ffa2881d12fc1ce5e0e9 100644 (file)
@@ -1,11 +1,16 @@
 # ALSA USB drivers
 
-menu "USB devices"
-       depends on SND!=n && USB!=n
+menuconfig SND_USB
+       bool "USB sound devices"
+       depends on USB
+       default y
+       help
+         Support for sound devices connected via the USB bus.
+
+if SND_USB && USB
 
 config SND_USB_AUDIO
        tristate "USB Audio/MIDI driver"
-       depends on SND && USB
        select SND_HWDEP
        select SND_RAWMIDI
        select SND_PCM
@@ -18,7 +23,7 @@ config SND_USB_AUDIO
 
 config SND_USB_USX2Y
        tristate "Tascam US-122, US-224 and US-428 USB driver"
-       depends on SND && USB && (X86 || PPC || ALPHA)
+       depends on X86 || PPC || ALPHA
        select SND_HWDEP
        select SND_RAWMIDI
        select SND_PCM
@@ -31,7 +36,6 @@ config SND_USB_USX2Y
 
 config SND_USB_CAIAQ
        tristate "Native Instruments USB audio devices"
-       depends on SND && USB
        select SND_HWDEP
        select SND_RAWMIDI
        select SND_PCM
@@ -63,5 +67,5 @@ config SND_USB_CAIAQ_INPUT
           * Native Instruments Kore Controller 2
           * Native Instruments Audio Kontrol 1
 
-endmenu
+endif  # SND_USB
 
index 24970a5c888f6e2f26453712a3b12cfd544b5355..b3a60332583534735cfd54504cc8141cdb4587cd 100644 (file)
@@ -637,6 +637,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO):
                dev->samplerates |= SNDRV_PCM_RATE_88200;
                dev->samplerates |= SNDRV_PCM_RATE_192000;
                break;
index a972f77bd7856e6d9bf400f79923bb7d1ecafebc..83175083e50f8c60852cc0250fd26ace2038afba 100644 (file)
 #endif
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.6");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
                         "{Native Instruments, Kore Controller},"
                         "{Native Instruments, Kore Controller 2},"
-                        "{Native Instruments, Audio Kontrol 1}"
-                        "{Native Instruments, Audio 8 DJ}}");
+                        "{Native Instruments, Audio Kontrol 1},"
+                        "{Native Instruments, Audio 8 DJ},"
+                        "{Native Instruments, Session I/O}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -110,6 +111,11 @@ static struct usb_device_id snd_usb_id_table[] = {
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
                .idProduct =    USB_PID_AUDIO8DJ
        },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_SESSIONIO
+       },
        { /* terminator */ }
 };
 
index 96a491379c6062b540ff2a063f64735f1e2f640e..f9fbdbae269d21491d2dc84f726cfc12cdf51261 100644 (file)
@@ -11,6 +11,7 @@
 #define USB_PID_KORECONTROLLER2        0x4712
 #define USB_PID_AK1            0x0815
 #define USB_PID_AUDIO8DJ       0x1978
+#define USB_PID_SESSIONIO      0x1915
 
 #define EP1_BUFSIZE 64
 #define CAIAQ_USB_STR_LEN 0xff
index 410be4aff1baed739dac2d88fa178d58f640e993..b8cfb7c2276872a05f40a07a0ed57d0b57357e8e 100644 (file)
@@ -819,10 +819,6 @@ static const char *usb_error_string(int err)
                return "device disabled";
        case -EHOSTUNREACH:
                return "device suspended";
-#ifndef CONFIG_USB_EHCI_SPLIT_ISO
-       case -ENOSYS:
-               return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub";
-#endif
        case -EINVAL:
        case -EAGAIN:
        case -EFBIG:
index 82a8d14c26af26671513990291db6426c2de05c4..9ea726c049c6c1f5d7b891e2e25bcd62ff934e40 100644 (file)
@@ -210,6 +210,11 @@ YAMAHA_DEVICE(0x1042, NULL),
 YAMAHA_DEVICE(0x1043, NULL),
 YAMAHA_DEVICE(0x1044, NULL),
 YAMAHA_DEVICE(0x1045, NULL),
+YAMAHA_INTERFACE(0x104e, 0, NULL),
+YAMAHA_DEVICE(0x104f, NULL),
+YAMAHA_DEVICE(0x1050, NULL),
+YAMAHA_DEVICE(0x1051, NULL),
+YAMAHA_DEVICE(0x1052, NULL),
 YAMAHA_DEVICE(0x2000, "DGP-7"),
 YAMAHA_DEVICE(0x2001, "DGP-5"),
 YAMAHA_DEVICE(0x2002, NULL),
@@ -1379,6 +1384,39 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+{
+       /* Roland SonicCell */
+       USB_DEVICE(0x0582, 0x00c2),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "SonicCell",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
+
 /* Guillemot devices */
 {
        /*